diff --git a/.gitignore b/.gitignore index 1435f0b..d50415b 100644 --- a/.gitignore +++ b/.gitignore @@ -339,3 +339,13 @@ ASALocalRun/ # BeatPulse healthcheck temp database healthchecksdb + +# Fallback portraits for Houbr's Towers/Heros +# Don't know how to make the fallback portraits work lol +Resources/Buttons/FallbackPortrait/ArmyBasePortrait.png +Resources/Buttons/FallbackPortrait/BannerMonkeyPortrait.png +Resources/Buttons/FallbackPortrait/BoxerPortrait.png +Resources/Buttons/FallbackPortrait/FrankensteinPortrait.png +Resources/Buttons/FallbackPortrait/PsychomonkeyPortrait.png +Resources/Buttons/FallbackPortrait/MonkeyMachinePortrait.png +.editorconfig diff --git a/BTD6Rogue.cs b/BTD6Rogue.cs index 3644c71..5c1a176 100644 --- a/BTD6Rogue.cs +++ b/BTD6Rogue.cs @@ -1,6 +1,12 @@ using MelonLoader; using BTD_Mod_Helper; using BTD6Rogue; +using Il2CppAssets.Scripts.Simulation.Bloons; +using Il2CppInterop.Runtime; +using MelonLoader.NativeUtils; +using System.Runtime.InteropServices; +using HarmonyLib; + [assembly: MelonInfo(typeof(BTD6Rogue.BTD6Rogue), ModHelperData.Name, ModHelperData.Version, ModHelperData.RepoOwner)] [assembly: MelonGame("Ninja Kiwi", "BloonsTD6")] @@ -9,7 +15,7 @@ namespace BTD6Rogue; // Handles the creation of the RogueGame instance and logging // Outside of this functionality, BTD6Rogue should not be used to keep code organized -public class BTD6Rogue : BloonsTD6Mod { +public partial class BTD6Rogue : BloonsTD6Mod { // Static instance of BTD6 Rogue, makes it easy to access lol public static BTD6Rogue mod = null!; @@ -30,27 +36,37 @@ public override void OnApplicationQuit() { fileManager.SavePlayerStats(playerStats); } - // Use this static function instead of ModHelper.Msg to keep the logging consistent - // Info Logs are informational logs that are meant to be read by the end user but are't disrupting the gameplay or the mod - // Warning Logs are known issues/causes of issues but won't disrupt gameplay or the mod - // Error Logs are issues that will disrupt gameplay or the mod - // Critical Logs are issues that cause crashes, extreme bugs, errors, etc - // Debug is used in development for testing, they should not be sent in release versions - public static void LogMessage(object message, object caller = null!, ErrorLevels errorLevel = ErrorLevels.Debug) { - caller ??= "null"; - - if (errorLevel == (ErrorLevels) 0 && RogueModSettings.LogInfoMessages) { - ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Info) " + caller + ": " + message); - } else if (errorLevel == (ErrorLevels) 1 && RogueModSettings.LogWarningMessages) { - ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Warning) " + caller + ": " + message); - } else if (errorLevel == (ErrorLevels) 2 && RogueModSettings.LogErrorMessages) { - ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Error) " + caller + ": " + message); - } else if (errorLevel == (ErrorLevels) 3 && RogueModSettings.LogCriticalMessages) { - ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Critical) " + caller + ": " + message); - } else if (errorLevel == (ErrorLevels) 4 && RogueModSettings.LogDebugMessages) { - ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Debug) " + caller + ": " + message); - } - } + // Use this static function instead of ModHelper.Msg to keep the logging consistent + // Info Logs are informational logs that are meant to be read by the end user but are't disrupting the gameplay or the mod + // Warning Logs are known issues/causes of issues but won't disrupt gameplay or the mod + // Error Logs are issues that will disrupt gameplay or the mod + // Critical Logs are issues that cause crashes, extreme bugs, errors, etc + // Debug is used in development for testing, they should not be sent in release versions + public static void LogMessage(object message, object caller = null!, ErrorLevels errorLevel = ErrorLevels.Debug) + { + caller ??= "null"; + + if (errorLevel == (ErrorLevels)0 && RogueModSettings.LogInfoMessages) + { + ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Info) " + caller + ": " + message); + } + else if (errorLevel == (ErrorLevels)1 && RogueModSettings.LogWarningMessages) + { + ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Warning) " + caller + ": " + message); + } + else if (errorLevel == (ErrorLevels)2 && RogueModSettings.LogErrorMessages) + { + ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Error) " + caller + ": " + message); + } + else if (errorLevel == (ErrorLevels)3 && RogueModSettings.LogCriticalMessages) + { + ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Critical) " + caller + ": " + message); + } + else if (errorLevel == (ErrorLevels)4 && RogueModSettings.LogDebugMessages) + { + ModHelper.Msg("[BTD6Rogue-v" + ModHelperData.Version + "] (Debug) " + caller + ": " + message); + } + } } // Error levels for logging a message with the static LogMessage function diff --git a/BTD6Rogue.csproj b/BTD6Rogue.csproj index 60ccea9..68b62df 100644 --- a/BTD6Rogue.csproj +++ b/BTD6Rogue.csproj @@ -1,4 +1,4 @@ - + net6.0 BTD6Rogue @@ -8,6 +8,7 @@ latest False embedded + true @@ -30,12 +31,15 @@ - + + + + @@ -50,7 +54,17 @@ - + + + + + + + + + + + @@ -62,5 +76,19 @@ + + + + + + + + + + + + + + diff --git a/Bloon/BloonUtil.cs b/Bloon/BloonUtil.cs index 2a717e0..401d569 100644 --- a/Bloon/BloonUtil.cs +++ b/Bloon/BloonUtil.cs @@ -1,10 +1,56 @@ using BTD_Mod_Helper.Api; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Unity; +using Il2CppAssets.Scripts.Unity.Achievements.List; +using System.Linq; namespace BTD6Rogue; public static class BloonUtil { - public static RogueBloon[] GetAllBloons() { - return ModContent.GetContent().ToArray(); + return ModContent.GetContent() + .Where(bloon => { + try + { + ValidateRogueBloon(bloon); + return true; + } + catch + { + return false; + } + }).ToArray(); + } + + public static void ValidateRogueBloon(RogueBloon bloon) + { + string?[] arr = [bloon.BaseBloonId, null, null, null, null, null, null, null]; // + string[] brr = ["", "Camo", "Fortified", "FortifiedCamo", "Regrow", "RegrowCamo", "RegrowFortified", "RegrowFortifiedCamo"]; //Suffixes + + if (bloon.Camo) { arr[1] = bloon.BaseBloonId + brr[1]; } + if (bloon.Fortified) { arr[2] = bloon.BaseBloonId + brr[2]; } + if (bloon.Camo && bloon.Fortified) { arr[3] = bloon.BaseBloonId + brr[3]; } + if (bloon.Regrow) { arr[4] = bloon.BaseBloonId + brr[4]; } + if (bloon.Regrow && bloon.Camo) { arr[5] = bloon.BaseBloonId + brr[5]; } + if (bloon.Regrow && bloon.Fortified) { arr[6] = bloon.BaseBloonId + brr[6]; } + if (bloon.Regrow && bloon.Fortified && bloon.Camo) { arr[7] = bloon.BaseBloonId + brr[7]; } + + foreach (var j in arr) //Nullable string array + { + if (j is null) { continue; } + bool found = false; + foreach (var i in Game.instance.model.bloons) // Il2CppReferenceArray + { + if (i.id == j) + { + found = true; + break; // Exit loop when a match is found + } + } + if (!found) + { + BTD6Rogue.LogMessage($"The {j} Bloon was not found. It may cause a crash ingame.", typeof(BloonUtil), ErrorLevels.Debug); + } + } } } \ No newline at end of file diff --git a/Bloon/Bosses/BossUtil.cs b/Bloon/Bosses/BossUtil.cs index 2256dbc..5dd7a7b 100644 --- a/Bloon/Bosses/BossUtil.cs +++ b/Bloon/Bosses/BossUtil.cs @@ -44,7 +44,11 @@ public static string GetBossHint(string boss) { "A sudden ripple in the cosmos can be felt" }; - switch (boss) { + List BlastapopoulosHints = new List() { + "It's kinda hot" + }; + + switch (boss) { case "RogueBloonarius": return BloonariusHints[new Random().Next(BloonariusHints.Count)]; case "RogueVortex": @@ -55,7 +59,9 @@ public static string GetBossHint(string boss) { return DreadbloonHints[new Random().Next(DreadbloonHints.Count)]; case "RoguePhayze": return PhayzeHints[new Random().Next(PhayzeHints.Count)]; - } + case "RogueBlastapopoulos": + return BlastapopoulosHints[new Random().Next(PhayzeHints.Count)]; + } return "Error Message Lol"; } diff --git a/Bloon/RogueBloon.cs b/Bloon/RogueBloon.cs index fcac142..f5f2fd7 100644 --- a/Bloon/RogueBloon.cs +++ b/Bloon/RogueBloon.cs @@ -2,6 +2,7 @@ using Il2CppAssets.Scripts.Data.Knowledge.RelicKnowledge; using Il2CppAssets.Scripts.Models.Rounds; using System; +using System.Linq; namespace BTD6Rogue; @@ -9,8 +10,10 @@ namespace BTD6Rogue; // To Do: allow for custom modifiers instead of just vanilla stuff public abstract class RogueBloon : NamedModContent { public abstract string BaseBloonId { get; } // Base ID of the bloon (only need the Base Bloon, modifiers are handled inside class) + public virtual string? MasteryBloonId { get; } // Base ID of the bloon in mastery mode. + public virtual int MasteryMult => 1; // - public virtual int StartRound => -1; // The lowest round number where this bloon can spawn + public virtual int StartRound => -1; // The lowest round number where this bloon can spawn public virtual int EndRound => -1; // The highest round number where this bloon can spawn public virtual int MinAmount => 1; // Minimum amount of these bloons that can spawn while spawning @@ -18,27 +21,37 @@ public abstract class RogueBloon : NamedModContent { public virtual int BloonRbe => 1; // The "Red Bloon Equivalent" of the bloon public virtual bool MoabClass => false; - - // Whether or not the modifier exists on the bloon - // The round it can start spawning it - // The round it stops spawning it - - public virtual bool Camo => false; - public virtual int CamoStartRound => 0; + public virtual bool MoabClassMastery => false; + + // Whether or not the modifier exists on the bloon + // Ditto but for the Mastery mode (null uses the normal value) + // Whether to always force the modifier on the bloon (ie. DDTs) + // The round it can start spawning it + // The round it stops spawning it + + public virtual bool Camo => false; + public virtual bool? CamoIfMastery => null; + public virtual bool ForceCamo => false; + public virtual int CamoStartRound => 0; public virtual int CamoEndRound => 0; public virtual bool Regrow => false; - public virtual int RegrowStartRound => 0; + public virtual bool? RegrowIfMastery => null; + public virtual bool ForceRegrow => false; + public virtual int RegrowStartRound => 0; public virtual int RegrowEndRound => 0; public virtual bool Fortified => false; - public virtual int FortifiedStartRound => 0; + public virtual bool? FortifiedIfMastery => null; + public virtual bool ForceFortified => false; + public virtual int FortifiedStartRound => 0; public virtual int FortifiedEndRound => 0; - public virtual BloonGroupModel GenerateBloonGroup(int round, float expectedRbe, float start, float end, bool camo, bool regrow, bool fortified) { + public virtual BloonGroupModel GenerateBloonGroup(int round, float expectedRbe, float start, float end, bool camo, bool regrow, bool fortified) { int bloonAmount = GetBloonAmount(round, expectedRbe, fortified); - string newBloonId = BaseBloonId; + string newBloonId = BaseBloonId; + if (BTD6Rogue.rogueGame.modifiers.Any(m => m is OAMasteryModeModifier) && MasteryBloonId is not null) { newBloonId = MasteryBloonId; bloonAmount *= MasteryMult; } if (regrow) { newBloonId += "Regrow"; } if (fortified) { newBloonId += "Fortified"; } diff --git a/Bloon/Vanilla/BadBloon.cs b/Bloon/Vanilla/BadBloon.cs index 92f574b..61ad58e 100644 --- a/Bloon/Vanilla/BadBloon.cs +++ b/Bloon/Vanilla/BadBloon.cs @@ -2,6 +2,7 @@ public class BadBloon : RogueBloon { public override string BaseBloonId => "Bad"; + public override int MasteryMult => 6; public override int StartRound => 100; public override int EndRound => -1; diff --git a/Bloon/Vanilla/BfbBloon.cs b/Bloon/Vanilla/BfbBloon.cs index 6459f27..c4c1d2c 100644 --- a/Bloon/Vanilla/BfbBloon.cs +++ b/Bloon/Vanilla/BfbBloon.cs @@ -2,6 +2,7 @@ public class BfbBloon : RogueBloon { public override string BaseBloonId => "Bfb"; + public override string MasteryBloonId => "Zomg"; public override int StartRound => 60; public override int EndRound => -1; diff --git a/Bloon/Vanilla/BlackBloon.cs b/Bloon/Vanilla/BlackBloon.cs index abeaf73..0ff4b7c 100644 --- a/Bloon/Vanilla/BlackBloon.cs +++ b/Bloon/Vanilla/BlackBloon.cs @@ -2,6 +2,7 @@ public class BlackBloon : RogueBloon { public override string BaseBloonId => "Black"; + public override string MasteryBloonId => "White"; public override int StartRound => 18; public override int EndRound => 39; diff --git a/Bloon/Vanilla/BlueBloon.cs b/Bloon/Vanilla/BlueBloon.cs index a8843b9..49b16fc 100644 --- a/Bloon/Vanilla/BlueBloon.cs +++ b/Bloon/Vanilla/BlueBloon.cs @@ -2,6 +2,7 @@ public class BlueBloon : RogueBloon { public override string BaseBloonId => "Blue"; + public override string MasteryBloonId => "Green"; public override int StartRound => 3; public override int EndRound => 14; diff --git a/Bloon/Vanilla/CeramicBloon.cs b/Bloon/Vanilla/CeramicBloon.cs index 8a6f6c2..b342110 100644 --- a/Bloon/Vanilla/CeramicBloon.cs +++ b/Bloon/Vanilla/CeramicBloon.cs @@ -2,15 +2,18 @@ public class CeramicBloon : RogueBloon { public override string BaseBloonId => "Ceramic"; + public override string MasteryBloonId => "Moab"; public override int StartRound => 39; public override int EndRound => -1; public override int BloonRbe => 104; public override bool Camo => true; + public override bool? CamoIfMastery => false; public override int CamoStartRound => 62; public override int CamoEndRound => -1; public override bool Regrow => true; + public override bool? RegrowIfMastery => false; public override int RegrowStartRound => 47; public override int RegrowEndRound => -1; public override bool Fortified => true; diff --git a/Bloon/Vanilla/DdtBloon.cs b/Bloon/Vanilla/DdtBloon.cs index 39847cd..ff7f9ef 100644 --- a/Bloon/Vanilla/DdtBloon.cs +++ b/Bloon/Vanilla/DdtBloon.cs @@ -1,14 +1,21 @@ namespace BTD6Rogue; public class DdtBloon : RogueBloon { - public override string BaseBloonId => "Ddt"; + public override string BaseBloonId => "Ddt"; //wait were we using the decamoed DDT? + public override int MasteryMult => 6; public override int StartRound => 90; public override int EndRound => -1; public override int BloonRbe => 816; public override bool MoabClass => true; - public override bool Fortified => true; + + public override bool Camo => true; + public override bool ForceCamo => true; + public override int CamoStartRound => 90; + public override int CamoEndRound => -1; + + public override bool Fortified => true; public override int FortifiedStartRound => 110; public override int FortifiedEndRound => -1; } diff --git a/Bloon/Vanilla/GreenBloon.cs b/Bloon/Vanilla/GreenBloon.cs index f3d8b45..1683cf0 100644 --- a/Bloon/Vanilla/GreenBloon.cs +++ b/Bloon/Vanilla/GreenBloon.cs @@ -2,6 +2,7 @@ public class GreenBloon : RogueBloon { public override string BaseBloonId => "Green"; + public override string MasteryBloonId => "Yellow"; public override int StartRound => 6; public override int EndRound => 18; diff --git a/Bloon/Vanilla/LeadBloon.cs b/Bloon/Vanilla/LeadBloon.cs index df910b5..07fbc94 100644 --- a/Bloon/Vanilla/LeadBloon.cs +++ b/Bloon/Vanilla/LeadBloon.cs @@ -2,6 +2,7 @@ public class LeadBloon : RogueBloon { public override string BaseBloonId => "Lead"; + public override string MasteryBloonId => "Zebra"; public override int StartRound => 28; public override int EndRound => -1; @@ -14,6 +15,7 @@ public class LeadBloon : RogueBloon { public override int RegrowStartRound => 46; public override int RegrowEndRound => -1; public override bool Fortified => true; + public override bool? FortifiedIfMastery => false; public override int FortifiedStartRound => 51; public override int FortifiedEndRound => -1; } diff --git a/Bloon/Vanilla/MoabBloon.cs b/Bloon/Vanilla/MoabBloon.cs index 265379f..9437b98 100644 --- a/Bloon/Vanilla/MoabBloon.cs +++ b/Bloon/Vanilla/MoabBloon.cs @@ -2,6 +2,7 @@ public class MoabBloon : RogueBloon { public override string BaseBloonId => "Moab"; + public override string MasteryBloonId => "Bfb"; public override int StartRound => 40; public override int EndRound => -1; diff --git a/Bloon/Vanilla/PinkBloon.cs b/Bloon/Vanilla/PinkBloon.cs index e4001ab..45b21a7 100644 --- a/Bloon/Vanilla/PinkBloon.cs +++ b/Bloon/Vanilla/PinkBloon.cs @@ -2,6 +2,7 @@ public class PinkBloon : RogueBloon { public override string BaseBloonId => "Pink"; + public override string MasteryBloonId => "Black"; public override int StartRound => 14; public override int EndRound => 30; diff --git a/Bloon/Vanilla/PurpleBloon.cs b/Bloon/Vanilla/PurpleBloon.cs index ced4a55..f911649 100644 --- a/Bloon/Vanilla/PurpleBloon.cs +++ b/Bloon/Vanilla/PurpleBloon.cs @@ -2,6 +2,7 @@ public class PurpleBloon : RogueBloon { public override string BaseBloonId => "Purple"; + public override string MasteryBloonId => "Lead"; public override int StartRound => 32; public override int EndRound => -1; diff --git a/Bloon/Vanilla/RainbowBloon.cs b/Bloon/Vanilla/RainbowBloon.cs index dfecc29..a96b10a 100644 --- a/Bloon/Vanilla/RainbowBloon.cs +++ b/Bloon/Vanilla/RainbowBloon.cs @@ -2,6 +2,7 @@ public class RainbowBloon : RogueBloon { public override string BaseBloonId => "Rainbow"; + public override string MasteryBloonId => "Ceramic"; public override int StartRound => 36; public override int EndRound => -1; diff --git a/Bloon/Vanilla/RedBloon.cs b/Bloon/Vanilla/RedBloon.cs index c7cc38b..b0b3777 100644 --- a/Bloon/Vanilla/RedBloon.cs +++ b/Bloon/Vanilla/RedBloon.cs @@ -2,7 +2,8 @@ public class RedBloon : RogueBloon { public override string BaseBloonId => "Red"; - public override int StartRound => -999; + public override string MasteryBloonId => "Blue"; + public override int StartRound => -999; public override int EndRound => 12; public override int BloonRbe => 1; diff --git a/Bloon/Vanilla/WhiteBloon.cs b/Bloon/Vanilla/WhiteBloon.cs index 8dfc5fb..9522631 100644 --- a/Bloon/Vanilla/WhiteBloon.cs +++ b/Bloon/Vanilla/WhiteBloon.cs @@ -2,6 +2,7 @@ public class WhiteBloon : RogueBloon { public override string BaseBloonId => "White"; + public override string MasteryBloonId => "Purple"; public override int StartRound => 18; public override int EndRound => 39; diff --git a/Bloon/Vanilla/YellowBloon.cs b/Bloon/Vanilla/YellowBloon.cs index a720bfa..0b9938c 100644 --- a/Bloon/Vanilla/YellowBloon.cs +++ b/Bloon/Vanilla/YellowBloon.cs @@ -2,6 +2,7 @@ public class YellowBloon : RogueBloon { public override string BaseBloonId => "Yellow"; + public override string MasteryBloonId => "Pink"; public override int StartRound => 9; public override int EndRound => 23; diff --git a/Bloon/Vanilla/ZebraBloon.cs b/Bloon/Vanilla/ZebraBloon.cs index a35247b..7b22c7e 100644 --- a/Bloon/Vanilla/ZebraBloon.cs +++ b/Bloon/Vanilla/ZebraBloon.cs @@ -2,6 +2,7 @@ public class ZebraBloon : RogueBloon { public override string BaseBloonId => "Zebra"; + public override string MasteryBloonId => "Rainbow"; public override int StartRound => 31; public override int EndRound => -1; diff --git a/Bloon/Vanilla/ZomgBloon.cs b/Bloon/Vanilla/ZomgBloon.cs index 8aaa5c7..80e6b37 100644 --- a/Bloon/Vanilla/ZomgBloon.cs +++ b/Bloon/Vanilla/ZomgBloon.cs @@ -2,6 +2,7 @@ public class ZomgBloon : RogueBloon { public override string BaseBloonId => "Zomg"; + public override string MasteryBloonId => "Bad"; public override int StartRound => 80; public override int EndRound => -1; diff --git a/Encounter/Encounters/GainPrismaticEncounter.cs b/Encounter/Encounters/GainPrismaticEncounter.cs new file mode 100644 index 0000000..ef0de22 --- /dev/null +++ b/Encounter/Encounters/GainPrismaticEncounter.cs @@ -0,0 +1,37 @@ + +namespace BTD6Rogue; + +public class GainPrismaticEncounter : RogueEncounter { + public override bool CanStartEncounter() { + return true; + } + + public override void StartEncounter() { + BTD6Rogue.rogueGame.panelManager.AppendPanel("PrismChoicePanel", this, true); + } + + public override void EncounterPanelCreated() { } + + public override void ProcessChoice(EncounterChoice choice) { + if (choice is TowerChoice) { + TowerChoice towerChoice = (TowerChoice)choice; + TowerData towerData = TowerUtil.CreateDataFromChoice(towerChoice); + BTD6Rogue.rogueGame.towerManager.AddTowerToInventory(towerData); + EndEncounter(); + } + else if (choice is HeroChoice) + { + HeroChoice heroChoice = (HeroChoice)choice; + HeroData heroData = HeroUtil.CreateDataFromChoice(heroChoice); + BTD6Rogue.rogueGame.towerManager.AddHeroToInventory(heroData); + EndEncounter(); + } + else + { + BTD6Rogue.LogMessage("EncounterChoice instance passed to ProcessChoice from EncounterPanel isn't an instance of TowerChoice or HeroChoice.", this.Name, ErrorLevels.Error); + return; + } + } + + public override void EncounterPanelDestroyed() { } +} diff --git a/Encounter/Encounters/GameStartEncounter.cs b/Encounter/Encounters/GameStartEncounter.cs index 98719bb..7cb00b3 100644 --- a/Encounter/Encounters/GameStartEncounter.cs +++ b/Encounter/Encounters/GameStartEncounter.cs @@ -8,10 +8,30 @@ public override bool CanStartEncounter() { } public override void StartEncounter() { - if (!BTD6Rogue.rogueGame.towerManager.disabledTowerSets.Contains(Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Hero)) { BTD6Rogue.rogueGame.panelManager.AppendPanel("HeroSelectPanel", this); } - BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerSelectPanel", this); - BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerSelectPanel", this); - BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerSelectPanel", this, true); + if (ModifierUtil.HasModifier()) { + /*if (ModifierUtil.HasModifier()) + { + if (!BTD6Rogue.rogueGame.towerManager.disabledTowerSets.Contains(Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Hero)) { BTD6Rogue.rogueGame.panelManager.AppendPanel("PrismaticChoicePanel", this); } + BTD6Rogue.rogueGame.panelManager.AppendPanel("PrismaticChoicePanel", this); + BTD6Rogue.rogueGame.panelManager.AppendPanel("PrismaticChoicePanel", this); + BTD6Rogue.rogueGame.panelManager.AppendPanel("PrismaticChoicePanel", this); + return; + } + else*/ + { + if (!BTD6Rogue.rogueGame.towerManager.disabledTowerSets.Contains(Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Hero)) { BTD6Rogue.rogueGame.panelManager.AppendPanel("HeroChoicePanel", this); } + BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerChoicePanel", this); + BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerChoicePanel", this); + BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerChoicePanel", this, true); + return; + } + } + else { + if (!BTD6Rogue.rogueGame.towerManager.disabledTowerSets.Contains(Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Hero)) { BTD6Rogue.rogueGame.panelManager.AppendPanel("HeroSelectPanel", this); } + BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerSelectPanel", this); + if (!ModifierUtil.HasModifier()) { BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerSelectPanel", this); } + BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerSelectPanel", this, true); + } } public override void EncounterPanelCreated() {} diff --git a/Gamemode/Difficulty/RogueDifficulty.cs b/Gamemode/Difficulty/RogueDifficulty.cs index e49792c..535cdec 100644 --- a/Gamemode/Difficulty/RogueDifficulty.cs +++ b/Gamemode/Difficulty/RogueDifficulty.cs @@ -20,22 +20,25 @@ public List>> GetSendableRogueBloons(int round, i int adjustedRound = round + 1; // In code round is 1 less than displayed (index at 0 things) but in the data it's at display value so, need to adjust it foreach (RogueBloon bloon in allBloons) { - if (bloon.GetBloonRbe(round, false) > maxRbe) { continue; } - - Tuple> bloonData = new(bloon, []); - if (adjustedRound >= bloon.StartRound + BloonSendOffset && (adjustedRound <= bloon.EndRound + BloonSendOffset || bloon.EndRound == -1)) { - bloonData.Item2.Add("None"); + var isMastery = ModifierUtil.HasModifier(); + bool isBaseReady = false; + if (bloon.GetBloonRbe(round, false) > maxRbe) { continue; } + + Tuple> bloonData = new(bloon, []); + if ((adjustedRound >= bloon.StartRound + BloonSendOffset) && (adjustedRound <= bloon.EndRound + BloonSendOffset || bloon.EndRound == -1)) { + isBaseReady = true; + bloonData.Item2.Add("None"); } - if (bloon.Regrow && adjustedRound >= bloon.RegrowStartRound + BloonSendOffset && (adjustedRound <= bloon.RegrowEndRound + BloonSendOffset || bloon.EndRound == -1)) { + if ((isMastery && (bloon.RegrowIfMastery != null) ? (bool)bloon.RegrowIfMastery : bloon.Regrow) && ((adjustedRound >= bloon.RegrowStartRound + BloonSendOffset && (adjustedRound <= bloon.RegrowEndRound + BloonSendOffset || bloon.EndRound == -1) || (ModifierUtil.HasModifier() && isBaseReady)))) { bloonData.Item2.Add("Regrow"); } - if (bloon.Camo && adjustedRound >= bloon.CamoStartRound + BloonSendOffset && (adjustedRound <= bloon.CamoEndRound + BloonSendOffset || bloon.EndRound == -1)) { + if ((isMastery && (bloon.CamoIfMastery != null) ? (bool)bloon.CamoIfMastery : bloon.Camo) && ((adjustedRound >= bloon.CamoStartRound + BloonSendOffset && (adjustedRound <= bloon.CamoEndRound + BloonSendOffset || bloon.EndRound == -1) || (ModifierUtil.HasModifier() && isBaseReady)))) { bloonData.Item2.Add("Camo"); } - if (bloon.Fortified && adjustedRound >= bloon.FortifiedStartRound + BloonSendOffset && (adjustedRound <= bloon.FortifiedEndRound + BloonSendOffset || bloon.EndRound == -1)) { + if ((isMastery && (bloon.FortifiedIfMastery != null) ? (bool)bloon.FortifiedIfMastery : bloon.Fortified) && ((adjustedRound >= bloon.FortifiedStartRound + BloonSendOffset) && (adjustedRound <= bloon.FortifiedEndRound + BloonSendOffset || bloon.EndRound == -1) /*|| ModifierUtil.HasModifier()*/)) { if (bloon.GetBloonRbe(round, true) < maxRbe) { bloonData.Item2.Add("Fortified"); } } diff --git a/Interface/Menu/StartGameMenus/SelectModifiersMenu.cs b/Interface/Menu/StartGameMenus/SelectModifiersMenu.cs index 4a5e87c..01f12c5 100644 --- a/Interface/Menu/StartGameMenus/SelectModifiersMenu.cs +++ b/Interface/Menu/StartGameMenus/SelectModifiersMenu.cs @@ -40,7 +40,7 @@ public override bool OnMenuOpened(Object data) { if (x % 6 == 0) { currentRow = rogueMenu.AddPanel( new Info("ModifierRow", 2000, 400) { FlexWidth = 1, FlexHeight = 2 }, - null, RectTransform.Axis.Horizontal, 60, 60); + null, RectTransform.Axis.Horizontal, 50, 50); } var modifierCheckbox = currentRow.AddCheckbox( @@ -49,7 +49,7 @@ public override bool OnMenuOpened(Object data) { AspectRatioFitter arf = modifierCheckbox.AddComponent(); arf.aspectMode = AspectRatioFitter.AspectMode.HeightControlsWidth; - modifierCheckbox.AddText(new Info("", InfoPreset.FillParent), modifier.DisplayName, 72, Il2CppTMPro.TextAlignmentOptions.Bottom); + modifierCheckbox.AddText(new Info("", InfoPreset.FillParent), modifier.DisplayName, 60, Il2CppTMPro.TextAlignmentOptions.Bottom); x += 1; } diff --git a/Interface/Panels/HeroChoicePanel.cs b/Interface/Panels/HeroChoicePanel.cs index 4ae706c..6e9a95d 100644 --- a/Interface/Panels/HeroChoicePanel.cs +++ b/Interface/Panels/HeroChoicePanel.cs @@ -1,9 +1,11 @@ -using System; -using System.Linq; +using BTD_Mod_Helper.Api; using BTD_Mod_Helper.Api.Components; using BTD_Mod_Helper.Api.Enums; using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models.TowerSets; using MelonLoader; +using System; +using System.Linq; using UnityEngine; using UnityEngine.UI; @@ -41,20 +43,23 @@ public override void CreatePanel() { HeroChoice[] heroChoices = HeroUtil.CreateValidHeroChoices(BTD6Rogue.rogueGame); if (heroChoices == null) { BTD6Rogue.rogueGame.towerManager.UnlockAllHeroes(); heroChoices = HeroUtil.CreateValidHeroChoices(BTD6Rogue.rogueGame); } + if (ModifierUtil.HasModifier()) { var binaryChoices = heroChoices.ToList(); binaryChoices.Remove(binaryChoices.Last()); heroChoices = binaryChoices.ToArray(); } - for (int i = 0; i < heroChoices.Length; i++) { + for (int i = 0; i < heroChoices.Length; i++) { HeroChoice heroChoice = heroChoices[i]; BTD6Rogue.rogueGame.towerManager.LockHero(heroChoice.towerId); - ModHelperButton button = towerRow.AddButton(new Info("Tower Button", InfoPreset.Flex), VanillaSprites.TowerContainerHero, new Action(() => ChooseHero(heroChoice))); + ModHelperButton button = towerRow.AddButton(new Info("Tower Button", InfoPreset.Flex), heroChoice.towerModel.towerSet == TowerSet.Hero ? VanillaSprites.TowerContainerHero : ModContent.GetTextureGUID("TowerContainerNeutral"), new Action(() => ChooseHero(heroChoice))); AspectRatioFitter arf = button.gameObject.AddComponent(); arf.aspectMode = AspectRatioFitter.AspectMode.HeightControlsWidth; - ModHelperImage towerImage = button.AddImage(new Info("Image", InfoPreset.FillParent), heroChoice.towerImage.GetGUID()); + + ModHelperImage towerImage = button.AddImage(new Info("Image", InfoPreset.FillParent), heroChoice.towerImage.GetGUID()); + //GUID may not correspond to a image, if so it will display a white square - ModHelperText towerUpgradeName = towerImage.AddText(new Info("Tower Name", InfoPreset.FillParent) { AnchorMin = new(0.05f, 0.05f), AnchorMax = new(0.95f, 0.95f) }, heroChoice.towerId, 72, Il2CppTMPro.TextAlignmentOptions.Bottom); + ModHelperText towerUpgradeName = towerImage.AddText(new Info("Tower Name", InfoPreset.FillParent) { AnchorMin = new(0.05f, 0.05f), AnchorMax = new(0.95f, 0.95f) }, heroChoice.towerId, 72, Il2CppTMPro.TextAlignmentOptions.Bottom); } if (BTD6Rogue.rogueGame.rerolls > 0) { diff --git a/Interface/Panels/HeroSelectPanel.cs b/Interface/Panels/HeroSelectPanel.cs index 9c28f38..93c2fbb 100644 --- a/Interface/Panels/HeroSelectPanel.cs +++ b/Interface/Panels/HeroSelectPanel.cs @@ -2,6 +2,7 @@ using BTD_Mod_Helper.Api.Components; using BTD_Mod_Helper.Api.Enums; using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models.TowerSets; using MelonLoader; using UnityEngine; using UnityEngine.UI; @@ -33,7 +34,9 @@ public override void CreatePanel() { currentRow = towerSelectPanel.AddPanel(new Info("MapRow", InfoPreset.Flex), null, RectTransform.Axis.Horizontal, 50); } HeroChoice heroChoice = heroChoices[i]; - ModHelperButton button = currentRow.AddButton(new Info("Tower Button", InfoPreset.Flex), VanillaSprites.YellowBtn, new Action(() => ChooseHero(heroChoice))); + if (heroChoice.rogueTower.SelectBlacklisted) { continue; } + ModHelperButton button = currentRow.AddButton(new Info("Tower Button", InfoPreset.Flex), heroChoice.towerModel.towerSet == TowerSet.Hero ? VanillaSprites.YellowBtn : VanillaSprites.BlueBtn, new Action(() => ChooseHero(heroChoice))); + AspectRatioFitter arf = button.gameObject.AddComponent(); arf.aspectMode = AspectRatioFitter.AspectMode.HeightControlsWidth; button.AddImage(new Info("Image") { AnchorMin = new Vector2(0, 0), AnchorMax = new Vector2(1, 1), Size = 50 }, heroChoice.towerImage.GetGUID()); diff --git a/Interface/Panels/PanelManager.cs b/Interface/Panels/PanelManager.cs index bdf9edb..a2f5d3d 100644 --- a/Interface/Panels/PanelManager.cs +++ b/Interface/Panels/PanelManager.cs @@ -57,7 +57,10 @@ public void CheckQueue() { case "ParagonChoicePanel": panel.AddComponent(); break; - } + case "PrismChoicePanel": + panel.AddComponent(); + break; + } RoguePanel roguePanel = panel.GetComponent(); roguePanel.SetupPanel(InGame.instance, InGame.instance.uiRect, panel, panelEncounter); diff --git a/Interface/Panels/ParagonChoicePanel.cs b/Interface/Panels/ParagonChoicePanel.cs index 97c763e..af2c121 100644 --- a/Interface/Panels/ParagonChoicePanel.cs +++ b/Interface/Panels/ParagonChoicePanel.cs @@ -41,6 +41,7 @@ public override void CreatePanel() { ParagonChoice[] paragonChoices = ParagonUtil.CreateValidParagonChoices(BTD6Rogue.rogueGame); if (paragonChoices == null) { BTD6Rogue.rogueGame.towerManager.UnlockAllParagons(); paragonChoices = ParagonUtil.CreateValidParagonChoices(BTD6Rogue.rogueGame); } + if (ModifierUtil.HasModifier()) { var binaryChoices = paragonChoices.ToList(); binaryChoices.Remove(binaryChoices.Last()); paragonChoices = binaryChoices.ToArray(); } for (int i = 0; i < paragonChoices.Length; i++) { ParagonChoice paragonChoice = paragonChoices[i]; diff --git a/Interface/Panels/PrismChoicePanel.cs b/Interface/Panels/PrismChoicePanel.cs new file mode 100644 index 0000000..774468d --- /dev/null +++ b/Interface/Panels/PrismChoicePanel.cs @@ -0,0 +1,170 @@ +using BTD_Mod_Helper.Api; +using BTD_Mod_Helper.Api.Components; +using BTD_Mod_Helper.Api.Enums; +using BTD_Mod_Helper.Extensions; +using HarmonyLib; +using Il2CppAssets.Scripts.Models.Towers; +using Il2CppAssets.Scripts.Models.TowerSets; +using MelonLoader; +using System; +using System.Linq; +using UnityEngine; +using UnityEngine.UI; + +namespace BTD6Rogue; + +[RegisterTypeInIl2Cpp(false)] +public class PrismChoicePanel : RoguePanel { + public void ChooseTower(TowerChoice towerChoice) { + if (!active) { return; } + active = false; + encounter.ProcessChoice(towerChoice); + DestroyPanel(); + } + public void ChooseHero(HeroChoice heroChoice) + { + if (!active) { return; } + active = false; + encounter.ProcessChoice(heroChoice); + DestroyPanel(); + } + public void ChooseNull() + { + if (!active) { return; } + active = false; + DestroyPanel(); + } + + public void RerollTowers(EncounterChoice[] prismChoices, bool useReroll = true) { + if (!active) { return; } + active = false; + + foreach (EncounterChoice towerChoice in prismChoices) { + if (towerChoice is TowerChoice) + { + TowerChoice tc = (TowerChoice)towerChoice; + BTD6Rogue.rogueGame.towerManager.UnlockTowerPath(tc.towerId, Array.IndexOf(tc.towerPaths, tc.towerPaths.Max())); + } + else if (towerChoice is HeroChoice) + { + TowerChoice hc = (TowerChoice)towerChoice; + BTD6Rogue.rogueGame.towerManager.UnlockHero(hc.towerId); + } + } + if (useReroll) { BTD6Rogue.rogueGame.rerolls--; } + BTD6Rogue.rogueGame.panelManager.AppendPanel("TowerChoicePanel", encounter); + DestroyPanel(); + } + + public override void CreatePanel() { + ModHelperPanel borderPanel = parent.AddPanel(new Info("Border Panel") { AnchorMin = new(0.225f, 0.25f), AnchorMax = new Vector2(0.775f, 0.75f) }, VanillaSprites.BrownInsertPanelDark); + ModHelperPanel towerSelectPanel = borderPanel.AddPanel(new Info("Tower Select Panel", InfoPreset.FillParent), VanillaSprites.BrownInsertPanel, RectTransform.Axis.Vertical, 20, 40); + + ModHelperText chooseText = towerSelectPanel.AddText(new Info("Tower Amount", InfoPreset.Flex), "Choose a Path", 86); + ModHelperText infoText = towerSelectPanel.AddText(new Info("Tower Amount", InfoPreset.Flex), "None of these paths will show up again, choose wisely", 52); + ModHelperPanel towerRow = towerSelectPanel.AddPanel(new Info("MapRow", InfoPreset.Flex) { FlexHeight = 4 }, null, RectTransform.Axis.Horizontal, 50); + + EncounterChoice[] towerChoices = TowerUtil.CreateValidTowerChoices(BTD6Rogue.rogueGame); + EncounterChoice[] heroChoices = HeroUtil.CreateValidHeroChoices(BTD6Rogue.rogueGame); + if (heroChoices == null) { BTD6Rogue.rogueGame.towerManager.UnlockAllHeroes(); heroChoices = HeroUtil.CreateValidHeroChoices(BTD6Rogue.rogueGame); } + if (towerChoices == null) { BTD6Rogue.rogueGame.towerManager.UnlockAllTowers(); towerChoices = TowerUtil.CreateValidTowerChoices(BTD6Rogue.rogueGame); } + EncounterChoice[] prismChoices = towerChoices; + prismChoices.AddRangeToArray(heroChoices); + if (ModifierUtil.HasModifier()) { var binaryChoices = towerChoices.ToList(); binaryChoices.Remove(binaryChoices.Last()); towerChoices = binaryChoices.ToArray(); } + + for (int i = 0; i < prismChoices.Length; i++) { + if (prismChoices[i] is TowerChoice) + { + TowerChoice towerChoice = (TowerChoice)prismChoices[i]; + if (towerChoice.towerModel is null) + { BTD6Rogue.rogueGame.towerManager.LockTowerPath(towerChoice.towerId, 0); BTD6Rogue.rogueGame.towerManager.LockTowerPath(towerChoice.towerId, 1); BTD6Rogue.rogueGame.towerManager.LockTowerPath(towerChoice.towerId, 2); i--; continue; } + BTD6Rogue.rogueGame.towerManager.LockTowerPath(towerChoice.towerId, Array.IndexOf(towerChoice.towerPaths, towerChoice.towerPaths.Max())); + + string buttonSprite = ModContent.GetTextureGUID("TowerContainerNeutral"); + string towerSet = towerChoice.towerModel.GetTowerSet(); + if (towerSet == "Hero") + { + buttonSprite = VanillaSprites.TowerContainerHero; + } + /*else if (towerSet == "Items" || towerSet == "PowersInShop-Powers" || towerSet == "SpecialAgents-SpecialAgentSet") { + buttonSprite = ModContent.GetTextureGUID("TowerContainerPower"); + }*/ + else if (towerSet == "Primary") + { + buttonSprite = VanillaSprites.TowerContainerPrimary; + } + else if (towerSet == "Military") + { + buttonSprite = VanillaSprites.TowerContainerMilitary; + } + else if (towerSet == "Magic") + { + buttonSprite = VanillaSprites.TowerContainerMagic; + } + else if (towerSet == "Support") + { + buttonSprite = VanillaSprites.TowerContainerSupport; + } + + ModHelperButton button = towerRow.AddButton(new Info("Tower Button", InfoPreset.Flex), buttonSprite, new Action(() => ChooseTower(towerChoice))); + + AspectRatioFitter arf = button.gameObject.AddComponent(); + arf.aspectMode = AspectRatioFitter.AspectMode.HeightControlsWidth; + + ModHelperImage towerImage = button.AddImage(new Info("Image", InfoPreset.FillParent), towerChoice.towerImage.GetGUID()); + + ModHelperText towerBaseName = towerImage.AddText(new Info("Tower Base Name", InfoPreset.FillParent) { AnchorMin = new(0.05f, 0.05f), AnchorMax = new(0.95f, 0.95f) }, towerChoice.towerId, 72, Il2CppTMPro.TextAlignmentOptions.Bottom); + ModHelperText towerUpgradeName = towerImage.AddText(new Info("Tower Name", InfoPreset.FillParent) { AnchorMin = new(0.05f, 0.05f), AnchorMax = new(0.95f, 0.95f) }, towerChoice.towerName, 72, Il2CppTMPro.TextAlignmentOptions.Top); + ModHelperText towerAmount = towerImage.AddText(new Info("Tower Amount", InfoPreset.FillParent) { AnchorMin = new(0.05f, 0.05f), AnchorMax = new(0.95f, 0.95f) }, towerChoice.towerAmount.ToString(), 96, Il2CppTMPro.TextAlignmentOptions.TopRight); + } + else if (prismChoices[i] is HeroChoice) + { + HeroChoice heroChoice = (HeroChoice)heroChoices[i]; + BTD6Rogue.rogueGame.towerManager.LockHero(heroChoice.towerId); + + ModHelperButton button = towerRow.AddButton(new Info("Tower Button", InfoPreset.Flex), heroChoice.towerModel.towerSet == TowerSet.Hero ? VanillaSprites.TowerContainerHero : ModContent.GetTextureGUID("TowerContainerNeutral"), new Action(() => ChooseHero(heroChoice))); + + AspectRatioFitter arf = button.gameObject.AddComponent(); + arf.aspectMode = AspectRatioFitter.AspectMode.HeightControlsWidth; + + + ModHelperImage towerImage = button.AddImage(new Info("Image", InfoPreset.FillParent), heroChoice.towerImage.GetGUID()); + //GUID may not correspond to a image, if so it will display a white square + + + ModHelperText towerUpgradeName = towerImage.AddText(new Info("Tower Name", InfoPreset.FillParent) { AnchorMin = new(0.05f, 0.05f), AnchorMax = new(0.95f, 0.95f) }, heroChoice.towerId, 72, Il2CppTMPro.TextAlignmentOptions.Bottom); + } + else + { + string buttonSprite = ModContent.GetTextureGUID("TowerContainerNeutral"); + ModHelperButton button = towerRow.AddButton(new Info("Tower Button", InfoPreset.Flex), buttonSprite, new Action(() => ChooseNull())); + } + } + + if (BTD6Rogue.rogueGame.rerolls > 0) { + ModHelperButton rerollButton = towerSelectPanel.AddButton(new Info("Reroll Button", InfoPreset.Flex) {}, VanillaSprites.BlueBtnLong, new Action(() => RerollTowers(towerChoices))); + AspectRatioFitter arf = rerollButton.gameObject.AddComponent(); + arf.aspectMode = AspectRatioFitter.AspectMode.HeightControlsWidth; + arf.aspectRatio = 3; + ModHelperText towerName = rerollButton.AddText(new Info("Tower Name", InfoPreset.FillParent), "Reroll: " + BTD6Rogue.rogueGame.rerolls, 64); + } + + active = true; + } + public static string GetFallbackPortrait(TowerModel tower) + { + if (tower.IsHero()) { + return ModContent.GetTextureGUID("UnknownHeroPortrait"); + } + if (tower.isParagon) { + return ModContent.GetTextureGUID("UnknownParagonPortrait"); + } + if (tower.isSubTower || tower.isGeraldoItem) { + return ModContent.GetTextureGUID("UnknownSubTowerPortrait"); + } + if (tower.GetTowerSet() == "Items" || tower.GetTowerSet() == "PowersInShop-Powers" || tower.GetTowerSet() == "SpecialAgents-SpecialAgentSet") { + return ModContent.GetTextureGUID("UnknownPowerPortrait"); + } + return ModContent.GetTextureGUID("UnknownTowerPortrait"); + } +} diff --git a/Interface/Panels/TowerChoicePanel.cs b/Interface/Panels/TowerChoicePanel.cs index ad8d250..7c47a9f 100644 --- a/Interface/Panels/TowerChoicePanel.cs +++ b/Interface/Panels/TowerChoicePanel.cs @@ -1,9 +1,12 @@ -using System; -using System.Linq; +using BTD_Mod_Helper.Api; using BTD_Mod_Helper.Api.Components; using BTD_Mod_Helper.Api.Enums; using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models.Towers; +using Il2CppAssets.Scripts.Models.TowerSets; using MelonLoader; +using System; +using System.Linq; using UnityEngine; using UnityEngine.UI; @@ -41,22 +44,36 @@ public override void CreatePanel() { TowerChoice[] towerChoices = TowerUtil.CreateValidTowerChoices(BTD6Rogue.rogueGame); if (towerChoices == null) { BTD6Rogue.rogueGame.towerManager.UnlockAllTowers(); towerChoices = TowerUtil.CreateValidTowerChoices(BTD6Rogue.rogueGame); } + if (ModifierUtil.HasModifier()) { var binaryChoices = towerChoices.ToList(); binaryChoices.Remove(binaryChoices.Last()); towerChoices = binaryChoices.ToArray(); } - for (int i = 0; i < towerChoices.Length; i++) { + for (int i = 0; i < towerChoices.Length; i++) { TowerChoice towerChoice = towerChoices[i]; - BTD6Rogue.rogueGame.towerManager.LockTowerPath(towerChoice.towerId, Array.IndexOf(towerChoice.towerPaths, towerChoice.towerPaths.Max())); + if (towerChoice.towerModel is null) + { BTD6Rogue.rogueGame.towerManager.LockTowerPath(towerChoice.towerId, 0); BTD6Rogue.rogueGame.towerManager.LockTowerPath(towerChoice.towerId, 1); BTD6Rogue.rogueGame.towerManager.LockTowerPath(towerChoice.towerId, 2); i--; continue; } + BTD6Rogue.rogueGame.towerManager.LockTowerPath(towerChoice.towerId, Array.IndexOf(towerChoice.towerPaths, towerChoice.towerPaths.Max())); - string buttonSprite = VanillaSprites.TowerContainerPrimary; + string buttonSprite = ModContent.GetTextureGUID("TowerContainerNeutral"); string towerSet = towerChoice.towerModel.GetTowerSet(); - if (towerSet == "Military") { + if (towerSet == "Hero") { + buttonSprite = VanillaSprites.TowerContainerHero; + } + /*else if (towerSet == "Items" || towerSet == "PowersInShop-Powers" || towerSet == "SpecialAgents-SpecialAgentSet") { + buttonSprite = ModContent.GetTextureGUID("TowerContainerPower"); + }*/ + else if (towerSet == "Primary") { + buttonSprite = VanillaSprites.TowerContainerPrimary; + } + else if (towerSet == "Military") { buttonSprite = VanillaSprites.TowerContainerMilitary; - } else if (towerSet == "Magic") { + } + else if (towerSet == "Magic") { buttonSprite = VanillaSprites.TowerContainerMagic; - } else if (towerSet == "Support") { + } + else if (towerSet == "Support") { buttonSprite = VanillaSprites.TowerContainerSupport; } - ModHelperButton button = towerRow.AddButton(new Info("Tower Button", InfoPreset.Flex), buttonSprite, new Action(() => ChooseTower(towerChoice))); + ModHelperButton button = towerRow.AddButton(new Info("Tower Button", InfoPreset.Flex), buttonSprite, new Action(() => ChooseTower(towerChoice))); AspectRatioFitter arf = button.gameObject.AddComponent(); arf.aspectMode = AspectRatioFitter.AspectMode.HeightControlsWidth; @@ -78,4 +95,20 @@ public override void CreatePanel() { active = true; } + public static string GetFallbackPortrait(TowerModel tower) + { + if (tower.IsHero()) { + return ModContent.GetTextureGUID("UnknownHeroPortrait"); + } + if (tower.isParagon) { + return ModContent.GetTextureGUID("UnknownParagonPortrait"); + } + if (tower.isSubTower || tower.isGeraldoItem) { + return ModContent.GetTextureGUID("UnknownSubTowerPortrait"); + } + if (tower.GetTowerSet() == "Items" || tower.GetTowerSet() == "PowersInShop-Powers" || tower.GetTowerSet() == "SpecialAgents-SpecialAgentSet") { + return ModContent.GetTextureGUID("UnknownPowerPortrait"); + } + return ModContent.GetTextureGUID("UnknownTowerPortrait"); + } } diff --git a/Interface/Panels/TowerSelectPanel.cs b/Interface/Panels/TowerSelectPanel.cs index 8c732b6..002715c 100644 --- a/Interface/Panels/TowerSelectPanel.cs +++ b/Interface/Panels/TowerSelectPanel.cs @@ -14,7 +14,7 @@ public class TowerSelectPanel : RoguePanel { public void ChooseTower(TowerChoice towerChoice) { if (!active) { return; } active = false; - towerChoice.towerAmount = 1; + towerChoice.towerAmount = towerChoice.rogueTower.GetTowerAmountForChoice(); encounter.ProcessChoice(towerChoice); DestroyPanel(); } @@ -29,12 +29,14 @@ public override void CreatePanel () { ModHelperPanel currentRow = null!; - for (int i = 0; i < towerChoices.Length; i++) { - if (i % gridWidth == 0) { + for (int i = 0; i < towerChoices.Length; i++) + { + if (i % gridWidth == 0) { currentRow = towerSelectPanel.AddPanel(new Info("MapRow", InfoPreset.Flex), null, RectTransform.Axis.Horizontal, 50); } - TowerChoice towerChoice = towerChoices[i]; - ModHelperButton button = currentRow.AddButton(new Info("Tower Button", InfoPreset.Flex), VanillaSprites.YellowBtn, new Action(() => ChooseTower(towerChoice))); + TowerChoice towerChoice = towerChoices[i]; + if (towerChoice.rogueTower.SelectBlacklisted) { continue; } + ModHelperButton button = currentRow.AddButton(new Info("Tower Button", InfoPreset.Flex), VanillaSprites.YellowBtn, new Action(() => ChooseTower(towerChoice))); AspectRatioFitter arf = button.gameObject.AddComponent(); arf.aspectMode = AspectRatioFitter.AspectMode.HeightControlsWidth; button.AddImage(new Info("Image") { AnchorMin = new Vector2(0, 0), AnchorMax = new Vector2(1, 1), Size = 50 }, towerChoice.towerImage.GetGUID()); diff --git a/Map/MapUtil.cs b/Map/MapUtil.cs index d2f51d8..c5cfcd9 100644 --- a/Map/MapUtil.cs +++ b/Map/MapUtil.cs @@ -9,9 +9,11 @@ public static RogueMap[] GetOrderedRogueMaps() { RogueMap[] orderedMapList = [ ModContent.GetContent()[0], - ModContent.GetContent()[0], + ModContent.GetContent()[0], + ModContent.GetContent()[0], ModContent.GetContent()[0], - ModContent.GetContent()[0], + ModContent.GetContent()[0], + ModContent.GetContent()[0], ModContent.GetContent()[0], ModContent.GetContent()[0], ModContent.GetContent()[0], @@ -32,7 +34,7 @@ public static RogueMap[] GetOrderedRogueMaps() { ModContent.GetContent()[0], ModContent.GetContent()[0], - ModContent.GetContent()[0], + ModContent.GetContent()[0], ModContent.GetContent()[0], ModContent.GetContent()[0], ModContent.GetContent()[0], @@ -56,7 +58,9 @@ public static RogueMap[] GetOrderedRogueMaps() { ModContent.GetContent()[0], ModContent.GetContent()[0], - ModContent.GetContent()[0], + ModContent.GetContent()[0], + ModContent.GetContent()[0], + ModContent.GetContent()[0], ModContent.GetContent()[0], ModContent.GetContent()[0], ModContent.GetContent()[0], diff --git a/Map/VanillaMaps/AdvancedMaps/EnchantedGlade.cs b/Map/VanillaMaps/AdvancedMaps/EnchantedGlade.cs new file mode 100644 index 0000000..e3b5ec7 --- /dev/null +++ b/Map/VanillaMaps/AdvancedMaps/EnchantedGlade.cs @@ -0,0 +1,20 @@ +using BTD_Mod_Helper.Api.Enums; +using Il2CppAssets.Scripts.Data.MapSets; + +namespace BTD6Rogue; + +public class EnchantedGlade : RogueMap { + + public override string InternalName => "EnchantedGlade"; + public override string MapName => "Enchanted Glade"; + + public override string MapImage => VanillaSprites.MapSelectEnchantedGladeMapButton; + + public override MapDifficulty GameDifficulty => MapDifficulty.Advanced; + public override int RogueDifficulty => 0; + + public override bool Water => true; + + public override float[] TrackLengths => [0f]; + public override int[] TrackTypes => [0]; +} diff --git a/Map/VanillaMaps/AdvancedMaps/LastResort.cs b/Map/VanillaMaps/AdvancedMaps/LastResort.cs new file mode 100644 index 0000000..7568af3 --- /dev/null +++ b/Map/VanillaMaps/AdvancedMaps/LastResort.cs @@ -0,0 +1,20 @@ +using BTD_Mod_Helper.Api.Enums; +using Il2CppAssets.Scripts.Data.MapSets; + +namespace BTD6Rogue; + +public class LastResort : RogueMap { + + public override string InternalName => "LastResort"; + public override string MapName => "Last Resort"; + + public override string MapImage => VanillaSprites.MapSelectLastResortMapButton; + + public override MapDifficulty GameDifficulty => MapDifficulty.Advanced; + public override int RogueDifficulty => 0; + + public override bool Water => true; + + public override float[] TrackLengths => [0f]; + public override int[] TrackTypes => [0]; +} diff --git a/Map/VanillaMaps/AdvancedMaps/SunsetGulch.cs b/Map/VanillaMaps/AdvancedMaps/SunsetGulch.cs new file mode 100644 index 0000000..82f1078 --- /dev/null +++ b/Map/VanillaMaps/AdvancedMaps/SunsetGulch.cs @@ -0,0 +1,20 @@ +using BTD_Mod_Helper.Api.Enums; +using Il2CppAssets.Scripts.Data.MapSets; + +namespace BTD6Rogue; + +public class SunsetGulch : RogueMap { + + public override string InternalName => "SunsetGulch"; + public override string MapName => "Sunset Gulch"; + + public override string MapImage => VanillaSprites.MapSelectSunsetGulchMapButton; + + public override MapDifficulty GameDifficulty => MapDifficulty.Advanced; + public override int RogueDifficulty => 0; + + public override bool Water => false; + + public override float[] TrackLengths => [0f]; + public override int[] TrackTypes => [0]; +} diff --git a/Map/VanillaMaps/BeginnerMaps/SpaPits.cs b/Map/VanillaMaps/BeginnerMaps/SpaPits.cs new file mode 100644 index 0000000..e410d94 --- /dev/null +++ b/Map/VanillaMaps/BeginnerMaps/SpaPits.cs @@ -0,0 +1,20 @@ +using BTD_Mod_Helper.Api.Enums; +using Il2CppAssets.Scripts.Data.MapSets; + +namespace BTD6Rogue; + +public class SpaPits : RogueMap { + + public override string InternalName => "SpaPits"; + public override string MapName => "Spa Pits"; + + public override string MapImage => VanillaSprites.MapSelectSpaPitsButton; + + public override MapDifficulty GameDifficulty => MapDifficulty.Beginner; + public override int RogueDifficulty => 0; + + public override bool Water => true; + + public override float[] TrackLengths => [0f]; + public override int[] TrackTypes => [0]; +} diff --git a/Map/VanillaMaps/BeginnerMaps/ThreeMinesAround.cs b/Map/VanillaMaps/BeginnerMaps/ThreeMinesAround.cs new file mode 100644 index 0000000..35d6057 --- /dev/null +++ b/Map/VanillaMaps/BeginnerMaps/ThreeMinesAround.cs @@ -0,0 +1,20 @@ +using BTD_Mod_Helper.Api.Enums; +using Il2CppAssets.Scripts.Data.MapSets; + +namespace BTD6Rogue; + +public class ThreeMinesAround : RogueMap { + + public override string InternalName => "ThreeMinesAround"; + public override string MapName => "Three Mines 'Round"; + + public override string MapImage => VanillaSprites.MapSelectThreeMinesAroundMapButton; + + public override MapDifficulty GameDifficulty => MapDifficulty.Beginner; + public override int RogueDifficulty => 0; + + public override bool Water => false; + + public override float[] TrackLengths => [0f]; + public override int[] TrackTypes => [0]; +} diff --git a/Map/VanillaMaps/ExpertMaps/TrickyTracks.cs b/Map/VanillaMaps/ExpertMaps/TrickyTracks.cs new file mode 100644 index 0000000..900c2a6 --- /dev/null +++ b/Map/VanillaMaps/ExpertMaps/TrickyTracks.cs @@ -0,0 +1,20 @@ +using BTD_Mod_Helper.Api.Enums; +using Il2CppAssets.Scripts.Data.MapSets; + +namespace BTD6Rogue; + +public class TrickyTracks : RogueMap { + + public override string InternalName => "TrickyTracks"; + public override string MapName => "Tricky Tracks"; + + public override string MapImage => VanillaSprites.MapSelectTrickyTracksButton; + + public override MapDifficulty GameDifficulty => MapDifficulty.Expert; + public override int RogueDifficulty => 0; + + public override bool Water => false; + + public override float[] TrackLengths => [0f]; + public override int[] TrackTypes => [0]; +} diff --git a/Map/VanillaMaps/IntermediateMaps/LostCrevasse.cs b/Map/VanillaMaps/IntermediateMaps/LostCrevasse.cs new file mode 100644 index 0000000..5300562 --- /dev/null +++ b/Map/VanillaMaps/IntermediateMaps/LostCrevasse.cs @@ -0,0 +1,20 @@ +using BTD_Mod_Helper.Api.Enums; +using Il2CppAssets.Scripts.Data.MapSets; + +namespace BTD6Rogue; + +public class LostCrevasse : RogueMap +{ + public override string InternalName => "LostCrevasse"; + public override string MapName => "Lost Crevasse"; + + public override string MapImage => VanillaSprites.MapSelectLostCrevasseMapButton; + + public override MapDifficulty GameDifficulty => MapDifficulty.Intermediate; + public override int RogueDifficulty => 0; + + public override bool Water => true; + + public override float[] TrackLengths => [0f]; + public override int[] TrackTypes => [0]; +} diff --git a/ModHelperData.cs b/ModHelperData.cs index 18d2fc5..31c6a52 100644 --- a/ModHelperData.cs +++ b/ModHelperData.cs @@ -1,8 +1,8 @@ namespace BTD6Rogue; public static class ModHelperData { - public const string WorksOnVersion = "46"; - public const string Version = "3.1.1"; + public const string WorksOnVersion = "52.0"; + public const string Version = "3.2.4"; //tbh this update should have been 3.1.2, idk why bumped the number for v46 public const string Name = "BTD6Rogue"; public const string Description = "Turn BTD6 into a Roguelike!" + @@ -19,16 +19,18 @@ public static class ModHelperData { "\n - 5 Custom Difficulties that each scale the strength bosses and bloons and the cost of towers and upgrades" + "\n - All 6 vanilla bosses rebalanced with auto-scaling in freeplay" + "\n - Randomly generated rounds using an RBE equation based off the vanilla rounds" + - "\n - 11 modifiers to make games more difficult including all of CHIMPS and Tower Set restrictions" + + "\n - 16 modifiers to make games more difficult including all of CHIMPS and Tower Set restrictions" + "\n - Custom save files to allow for Saving and Loading BTD6Rogue games and a viewable game history" + "\n - And probably more things that I haven't listed!" + "\n" + "\nFor support I recommend joining the Menddev Discord Server as that is where I am most active" + "\nContent Creators feel free to use this mod in any and all content, credit is appreciated but not required" + + "\n " + "\nDiscalimer:" + "\nThis mod mses around with A LOT of core features meaning" + "\nThere are 0 guarantees on not getting flagged when playing with this mod!"; - public const string RepoOwner = "mend-dev"; + public const string RepoOwner = "Derpy-Jacob-903"; + public const string Author = "mend-dev, Derpy-Jacob-903"; public const string RepoName = "BTD6Rogue"; } \ No newline at end of file diff --git a/Modifier/ModifierUtil.cs b/Modifier/ModifierUtil.cs index b9716cf..83ffaf7 100644 --- a/Modifier/ModifierUtil.cs +++ b/Modifier/ModifierUtil.cs @@ -36,4 +36,6 @@ public static void ResetModModelModifiers(ModModel model) { modifier.RemoveRogueModifier(model); } } + public static bool HasModifier() where T : RogueModifier => + BTD6Rogue.rogueGame.modifiers.Any(m => m is T); } \ No newline at end of file diff --git a/Modifier/Modifiers/NoPowersModifier.cs b/Modifier/Modifiers/NoPowersModifier.cs index ac49a57..4a46388 100644 --- a/Modifier/Modifiers/NoPowersModifier.cs +++ b/Modifier/Modifiers/NoPowersModifier.cs @@ -13,7 +13,7 @@ public class NoPowersModifier : RogueModifier { public override void ApplyRogueModifier(ModModel model) { model.RemoveMutator("LockPowers"); model.AddMutator(new LockTowerSetModModel("LockPowers", Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Items)); - } + } public override void RemoveRogueModifier(ModModel model) { model.RemoveMutator("LockPowers"); } diff --git a/Modifier/Modifiers/OAMasteryMode.cs b/Modifier/Modifiers/OAMasteryMode.cs new file mode 100644 index 0000000..b3bdd02 --- /dev/null +++ b/Modifier/Modifiers/OAMasteryMode.cs @@ -0,0 +1,16 @@ +using BTD_Mod_Helper.Api.Enums; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models; +using Il2CppAssets.Scripts.Models.Gameplay.Mods; + +namespace BTD6Rogue; + +public class OAMasteryModeModifier : RogueModifier { + public override string DisplayName => "Mastery Mode"; + public override string Description => ""; + public override string Image => VanillaSprites.AlternateBloonsIcon; + + public override void ApplyRogueModifier(ModModel model) {} + + public override void RemoveRogueModifier(ModModel model) {} +} diff --git a/Modifier/Modifiers/OBinaryModifier.cs b/Modifier/Modifiers/OBinaryModifier.cs new file mode 100644 index 0000000..a191ec2 --- /dev/null +++ b/Modifier/Modifiers/OBinaryModifier.cs @@ -0,0 +1,15 @@ +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models; +using Il2CppAssets.Scripts.Models.Gameplay.Mods; + +namespace BTD6Rogue; + +public class OBinaryModifier : RogueModifier { + public override string DisplayName => "Binary"; + public override string Description => "Choices only have 2 options. Start with only 2 Monkeys."; //"Choices only have 2 options. Start with only 2 Monkeys" + public override string Image => GetSpriteReference("ClassicModeImage").ToString(); + + public override void ApplyRogueModifier(ModModel model) {} + + public override void RemoveRogueModifier(ModModel model) {} +} diff --git a/Modifier/Modifiers/ODraftModifier.cs b/Modifier/Modifiers/ODraftModifier.cs new file mode 100644 index 0000000..1a3b94e --- /dev/null +++ b/Modifier/Modifiers/ODraftModifier.cs @@ -0,0 +1,15 @@ +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models; +using Il2CppAssets.Scripts.Models.Gameplay.Mods; + +namespace BTD6Rogue; + +public class ODraftModifier : RogueModifier { + public override string DisplayName => "Draft"; + public override string Description => "Starting Hero and Tower Selects are replaced with Choices"; //"Starting Hero and Tower Selects are replaced with Choices" + public override string Image => GetSpriteReference("ClassicModeImage").ToString(); + + public override void ApplyRogueModifier(ModModel model) {} + + public override void RemoveRogueModifier(ModModel model) {} +} diff --git a/Modifier/Modifiers/OForceCamoModifier.cs b/Modifier/Modifiers/OForceCamoModifier.cs new file mode 100644 index 0000000..522b3f3 --- /dev/null +++ b/Modifier/Modifiers/OForceCamoModifier.cs @@ -0,0 +1,16 @@ +using BTD_Mod_Helper.Api.Enums; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models; +using Il2CppAssets.Scripts.Models.Gameplay.Mods; + +namespace BTD6Rogue; + +public class OForceCamoModifier : RogueModifier { + public override string DisplayName => "All Camo"; + public override string Description => ""; // + public override string Image => VanillaSprites.CamoBloonIcon; + + public override void ApplyRogueModifier(ModModel model) {} + + public override void RemoveRogueModifier(ModModel model) {} +} diff --git a/Modifier/Modifiers/OForceFortifiedModifier.cs b/Modifier/Modifiers/OForceFortifiedModifier.cs new file mode 100644 index 0000000..192763c --- /dev/null +++ b/Modifier/Modifiers/OForceFortifiedModifier.cs @@ -0,0 +1,16 @@ +using BTD_Mod_Helper.Api.Enums; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models; +using Il2CppAssets.Scripts.Models.Gameplay.Mods; + +namespace BTD6Rogue; + +public class OForceFortifiedModifier : RogueModifier { + public override string DisplayName => "All Fortified"; + public override string Description => ""; //"" + public override string Image => VanillaSprites.FortifiedBloonIcon; + + public override void ApplyRogueModifier(ModModel model) {} + + public override void RemoveRogueModifier(ModModel model) {} +} diff --git a/Modifier/Modifiers/OForceLeadModifier.cs b/Modifier/Modifiers/OForceLeadModifier.cs new file mode 100644 index 0000000..8fbcf17 --- /dev/null +++ b/Modifier/Modifiers/OForceLeadModifier.cs @@ -0,0 +1,16 @@ +using BTD_Mod_Helper.Api.Enums; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models; +using Il2CppAssets.Scripts.Models.Gameplay.Mods; + +namespace BTD6Rogue; + +public class OForceLeadModifier : RogueModifier { + public override string DisplayName => "All Lead"; + public override string Description => ""; // + public override string Image => VanillaSprites.LeadBloonIcon; + + public override void ApplyRogueModifier(ModModel model) {} + + public override void RemoveRogueModifier(ModModel model) {} +} diff --git a/Modifier/Modifiers/OForceRegrowModifier.cs b/Modifier/Modifiers/OForceRegrowModifier.cs new file mode 100644 index 0000000..b41a961 --- /dev/null +++ b/Modifier/Modifiers/OForceRegrowModifier.cs @@ -0,0 +1,16 @@ +using BTD_Mod_Helper.Api.Enums; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models; +using Il2CppAssets.Scripts.Models.Gameplay.Mods; + +namespace BTD6Rogue; + +public class OForceRegrowModifier : RogueModifier { + public override string DisplayName => "All Regrow"; + public override string Description => ""; + public override string Image => VanillaSprites.RegrowBloonIcon; + + public override void ApplyRogueModifier(ModModel model) {} + + public override void RemoveRogueModifier(ModModel model) {} +} diff --git a/Modifier/Modifiers/OPrismaticShard.cs b/Modifier/Modifiers/OPrismaticShard.cs new file mode 100644 index 0000000..6d653d5 --- /dev/null +++ b/Modifier/Modifiers/OPrismaticShard.cs @@ -0,0 +1,15 @@ +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models; +using Il2CppAssets.Scripts.Models.Gameplay.Mods; + +namespace BTD6Rogue; + +public class OPrismaticShardModifier : RogueModifier { + public override string DisplayName => "Prismatic\nShard"; + public override string Description => "Tower and Hero Choices are replaced by Prismatic Choices, which include Monkeys and Heros"; //"Gain one less Monkey from Tower and Paragon Choices" + public override string Image => GetSpriteReference("ClassicModeImage").ToString(); + + public override void ApplyRogueModifier(ModModel model) {} + + public override void RemoveRogueModifier(ModModel model) {} +} diff --git a/Modifier/Modifiers/OScatterbrainModifier.cs b/Modifier/Modifiers/OScatterbrainModifier.cs new file mode 100644 index 0000000..1ef988a --- /dev/null +++ b/Modifier/Modifiers/OScatterbrainModifier.cs @@ -0,0 +1,15 @@ +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models; +using Il2CppAssets.Scripts.Models.Gameplay.Mods; + +namespace BTD6Rogue; + +public class OScatterbrainModifier : RogueModifier { + public override string DisplayName => "Scatterbrain"; + public override string Description => "Gain one less Monkey from Tower and Paragon Choices"; //"Gain one less Monkey from Tower and Paragon Choices" + public override string Image => GetSpriteReference("ClassicModeImage").ToString(); + + public override void ApplyRogueModifier(ModModel model) {} + + public override void RemoveRogueModifier(ModModel model) {} +} diff --git a/Patch/Bloon/Bloon_Degrade.cs b/Patch/Bloon/Bloon_Degrade.cs index c0c7afe..8fb96ac 100644 --- a/Patch/Bloon/Bloon_Degrade.cs +++ b/Patch/Bloon/Bloon_Degrade.cs @@ -1,14 +1,23 @@ -using HarmonyLib; +using BTD_Mod_Helper; +using BTD_Mod_Helper.Api.Hooks; +using BTD_Mod_Helper.Api.Hooks.BloonHooks; +using HarmonyLib; using Il2CppAssets.Scripts.Simulation.Bloons; +using Il2CppAssets.Scripts.Simulation.SimulationBehaviors; +using Il2CppAssets.Scripts.Simulation.Towers.Projectiles; +using Il2CppAssets.Scripts.Unity.UI_New.InGame; namespace BTD6Rogue; -[HarmonyPatch(typeof(Bloon), nameof(Bloon.Degrade))] -internal static class Bloon_Degrade { - [HarmonyPostfix] - private static void Postfix(Bloon __instance) { - if (__instance.bloonModel.isBoss) { - BTD6Rogue.rogueGame.roundManager.BossDefeated(); - } - } +partial class BTD6Rogue +{ + [HookTarget(typeof(BloonDegradeHook), HookTargetAttribute.EHookType.Postfix)] + public static bool PostDegradeHook(Bloon __instance) + { + if (__instance.bloonModel.isBoss) + { + BTD6Rogue.rogueGame.roundManager.BossDefeated(); + } + return true; + } } diff --git a/Patch/BossBloonManager/BossBloonManager_OnRoundStart.cs b/Patch/BossBloonManager/BossBloonManager_OnRoundStart.cs index 0d2baee..52e3182 100644 --- a/Patch/BossBloonManager/BossBloonManager_OnRoundStart.cs +++ b/Patch/BossBloonManager/BossBloonManager_OnRoundStart.cs @@ -7,8 +7,10 @@ namespace BTD6Rogue; internal static class BossBloonManager_OnRoundStart { [HarmonyPostfix] - private static bool Prefix(BossBloonManager __instance, int spawnedRound) { - if (__instance.GetNextBossSpawnRound().Value != spawnedRound) { return true; } + private static bool Prefix(BossBloonManager __instance, int spawnedRound) + { + if (BTD6Rogue.rogueGame == null) { return true; } + if (__instance.GetNextBossSpawnRound().Value != spawnedRound) { return true; } return false; } } diff --git a/Patch/BossBloonManager/BossBloonManager_SpawnBoss.cs b/Patch/BossBloonManager/BossBloonManager_SpawnBoss.cs index 168b72e..003ecb5 100644 --- a/Patch/BossBloonManager/BossBloonManager_SpawnBoss.cs +++ b/Patch/BossBloonManager/BossBloonManager_SpawnBoss.cs @@ -7,8 +7,10 @@ namespace BTD6Rogue; internal static class BossBloonManager_SpawnBoss { [HarmonyPostfix] - private static bool Prefix(BossBloonManager __instance) { - return false; + private static bool Prefix(BossBloonManager __instance) + { + if (BTD6Rogue.rogueGame == null) { return true; } + return false; } } diff --git a/Patch/InGame/InGame_Initialise.cs b/Patch/InGame/InGame_Initialise.cs index c4edf23..4960084 100644 --- a/Patch/InGame/InGame_Initialise.cs +++ b/Patch/InGame/InGame_Initialise.cs @@ -1,17 +1,28 @@ -using HarmonyLib; +using BTD_Mod_Helper.Api; +using BTD_Mod_Helper.Api.Components; +using BTD_Mod_Helper.Api.Enums; +using BTD_Mod_Helper.Extensions; +using HarmonyLib; +using Il2CppAssets.Scripts; +using Il2CppAssets.Scripts.Simulation.Bloons; using Il2CppAssets.Scripts.Unity.UI_New.InGame; -using Il2CppSystem; +using Il2CppAssets.Scripts.Unity.UI_New.InGame.Races; +using Il2CppNinjaKiwi.Common.ResourceUtils; using Il2CppSystem.Collections; +using Il2CppTMPro; +using MelonLoader; +using UnityEngine; +using UnityEngine.UI; namespace BTD6Rogue; [HarmonyPatch(typeof(InGame), nameof(InGame.Initialise))] -internal static class InGame_Initialise { +internal static class InGame_Initialise +{ - [HarmonyPostfix] - private static void Postfix(InGame __instance) { - IEnumerator enumer = __instance.InstantiateUiObject(__instance.inGameMenuDefs[15]); - enumer.MoveNext(); - enumer.MoveNext(); - } -} + [HarmonyPostfix] + private static void Postfix(InGame __instance) + { + //Instantiating the Boss UI used to be done here, now that's done in the `InGame_StartMatch` patch. + } +} \ No newline at end of file diff --git a/Patch/InGame/InGame_RoundEnd.cs b/Patch/InGame/InGame_RoundEnd.cs index 7c185c5..a9c5483 100644 --- a/Patch/InGame/InGame_RoundEnd.cs +++ b/Patch/InGame/InGame_RoundEnd.cs @@ -45,8 +45,10 @@ private static void Postfix(InGame __instance) { bossUi.Hide(); } - // Tower choice every 10 rounds (starting at 5) - if ((round + 1 - 5) >= 0 && (round + 1 - 5) % 10 == 0) { + //TODO: readd the prism choices here + + // Tower choice every 10 rounds (starting at 5) + if ((round + 1 - 5) >= 0 && (round + 1 - 5) % 10 == 0) { if (BTD6Rogue.rogueGame.rerolls < 3) { BTD6Rogue.rogueGame.rerolls++; } BTD6Rogue.rogueGame.encounterManager.AddEncounter(ModContent.GetContent()[0]); } diff --git a/Patch/InGame/InGame_StartMatch.cs b/Patch/InGame/InGame_StartMatch.cs index 2e00249..f2b6d3e 100644 --- a/Patch/InGame/InGame_StartMatch.cs +++ b/Patch/InGame/InGame_StartMatch.cs @@ -5,16 +5,26 @@ using Il2CppAssets.Scripts.Unity.UI_New.InGame; using Il2CppAssets.Scripts.Unity.UI_New.InGame.Races; using Il2CppNinjaKiwi.Common; +using Il2CppSystem.Collections; using UnityEngine; namespace BTD6Rogue; [HarmonyPatch(typeof(InGame), nameof(InGame.StartMatch))] -internal static class InGame_StartMatch { +internal static class InGame_StartMatch +{ [HarmonyPostfix] - private static void Postfix(InGame __instance, MapSaveDataModel mapSaveData, bool wasSaveOverwritten) { + private static void Postfix(InGame __instance, MapSaveDataModel mapSaveData, bool wasSaveOverwritten) + { if (BTD6Rogue.rogueGame == null) { return; } + + IEnumerator enumer = __instance.InstantiateUiObject(__instance.inGameMenuDefs[15]); + enumer.MoveNext(); + enumer.MoveNext(); + + + __instance.bridge.simulation.bossSpawnRounds = new int[] { 19, 39, 59, 79, 99, 119, 139, 159, 179, 199, 219, 239, 259, 279, 299 }; __instance.bridge.simulation.model.bossBloonType = "Bloonarius"; __instance.bridge.simulation.model.bossEliteMode = false; @@ -22,14 +32,17 @@ private static void Postfix(InGame __instance, MapSaveDataModel mapSaveData, boo __instance.bridge.simulation.map.spawner.bossBloonManager = bbm; bbm.Init(__instance.bridge.simulation); - Transform transform = __instance.GetInGameUI().transform.FindChildWithName("BossUi(Clone)"); - BossUI bossUi = transform.GetComponent(); - bossUi.Hide(); + /*Transform transform = __instance.GetInGameUI().transform.FindChildWithName("BossUi(Clone)"); + BossUI bossUi = transform.GetComponent(); + bossUi.Hide();*/ - BTD6Rogue.rogueGame.gameData.gameState = GameState.Loaded; - if (mapSaveData != null) { + BTD6Rogue.rogueGame.gameData.gameState = GameState.Loaded; + if (mapSaveData != null) + { BTD6Rogue.rogueGame.GameLoaded(__instance); - } else { + } + else + { BTD6Rogue.rogueGame.GameStarted(__instance); } } diff --git a/Patch/MenuManager/MenuManager_CloseMenuInternal.cs b/Patch/MenuManager/MenuManager_CloseMenuInternal.cs index 5212d40..7db9cda 100644 --- a/Patch/MenuManager/MenuManager_CloseMenuInternal.cs +++ b/Patch/MenuManager/MenuManager_CloseMenuInternal.cs @@ -9,15 +9,15 @@ namespace BTD6Rogue; -[HarmonyPatch(typeof(BTDMenuManager._CloseCurrentMenuInternal_d__57), nameof(BTDMenuManager._CloseCurrentMenuInternal_d__57.MoveNext))] +[HarmonyPatch(typeof(BTDMenuManager._CloseCurrentMenuInternal_d__71), nameof(BTDMenuManager._CloseCurrentMenuInternal_d__71.MoveNext))] static class MenuManager_CloseCurrentMenuInternal { [HarmonyPrefix] - static void Prefix(BTDMenuManager._CloseCurrentMenuInternal_d__57 __instance, out string __state) { + static void Prefix(BTDMenuManager._CloseCurrentMenuInternal_d__71 __instance, out string __state) { __state = __instance._menuName_5__2; Il2CppSystem.ValueTuple lastStackedMenu = __instance.__4__this.menuStack[__instance.__4__this.menuStack.Count - 1]; if (__instance.__1__state == 0 && lastStackedMenu.Item1.Contains("ModdedMenu")) { - __instance.__8__1 = new BTDMenuManager.__c__DisplayClass57_0(); + __instance.__8__1 = new BTDMenuManager.__c__DisplayClass71_0(); __instance.__8__1.__4__this = __instance.__4__this; __instance.__4__this.IsClosingOrOpeningMenu = true; __instance.__8__1.closingMenu = __instance.__4__this.currMenu; @@ -48,7 +48,7 @@ static void Prefix(BTDMenuManager._CloseCurrentMenuInternal_d__57 __instance, ou } } [HarmonyPostfix] - static void Postfix(BTDMenuManager._CloseCurrentMenuInternal_d__57 __instance, string __state) { + static void Postfix(BTDMenuManager._CloseCurrentMenuInternal_d__71 __instance, string __state) { if (__state != null && __state.Contains("ModdedMenu") && __instance.__4__this.menuStack.Count > 1) { string oldName = __state.Split("-")[0]; diff --git a/Patch/MenuManager/MenuManager_LoadSceneAsync.cs b/Patch/MenuManager/MenuManager_LoadSceneAsync.cs index b8f3687..c12ba20 100644 --- a/Patch/MenuManager/MenuManager_LoadSceneAsync.cs +++ b/Patch/MenuManager/MenuManager_LoadSceneAsync.cs @@ -9,10 +9,10 @@ namespace BTD6Rogue; -[HarmonyPatch(typeof(BTDMenuManager._LoadSceneAsync_d__34), nameof(BTDMenuManager._LoadSceneAsync_d__34.MoveNext))] +[HarmonyPatch(typeof(BTDMenuManager._LoadSceneAsync_d__47), nameof(BTDMenuManager._LoadSceneAsync_d__47.MoveNext))] static class MenuManager_LoadSceneAsync { [HarmonyPrefix] - static void Prefix(BTDMenuManager._LoadSceneAsync_d__34 __instance, out string __state) { + static void Prefix(BTDMenuManager._LoadSceneAsync_d__47 __instance, out string __state) { __state = __instance.sceneName; if (__instance.__1__state == 0 && __instance.sceneName.Contains("ModdedMenu")) { string oldName = __instance.sceneName.Split("-")[0]; @@ -23,7 +23,7 @@ static void Prefix(BTDMenuManager._LoadSceneAsync_d__34 __instance, out string _ } [HarmonyPostfix] - static void PostFix(BTDMenuManager._LoadSceneAsync_d__34 __instance, string __state) { + static void PostFix(BTDMenuManager._LoadSceneAsync_d__47 __instance, string __state) { if (__instance.__1__state == -1 && __state.Contains("ModdedMenu")) { Scene newScene = SceneManager.CreateScene(__state, new CreateSceneParameters()); Scene sceneFromName = SceneManager.GetSceneByName(__instance.sceneName); diff --git a/Patch/MenuManager/MenuManager_OpenMenuInternal.cs b/Patch/MenuManager/MenuManager_OpenMenuInternal.cs index c87bd6f..f6df168 100644 --- a/Patch/MenuManager/MenuManager_OpenMenuInternal.cs +++ b/Patch/MenuManager/MenuManager_OpenMenuInternal.cs @@ -14,10 +14,10 @@ namespace BTD6Rogue; // Praise the patch for it allows menus OF THE SAME TYPE TO BE STACKED OVER EACHOTHER!!! // TODO: Menus of the same type overwrite eachother in the stack making it so if you press the back button, in this case, it sends the user back to the main menu rather than the previous menu // TODO: Delete Il2Cpp and obfuscation from existence -[HarmonyPatch(typeof(BTDMenuManager._OpenMenuInternal_d__52), nameof(BTDMenuManager._OpenMenuInternal_d__52.MoveNext))] +[HarmonyPatch(typeof(BTDMenuManager._OpenMenuInternal_d__66), nameof(BTDMenuManager._OpenMenuInternal_d__66.MoveNext))] static class MenuManager_OpenMenuInternal { [HarmonyPrefix] - static void Prefix(BTDMenuManager._OpenMenuInternal_d__52 __instance) { + static void Prefix(BTDMenuManager._OpenMenuInternal_d__66 __instance) { bool isModdedMenu = false; ModMenuData mmd = null!; if (__instance.menuData != null) { @@ -28,7 +28,7 @@ static void Prefix(BTDMenuManager._OpenMenuInternal_d__52 __instance) { } if (__instance.__1__state == 0 && isModdedMenu) { __instance.__1__state = 1; - __instance.__8__1 = new BTDMenuManager.__c__DisplayClass52_0(); + __instance.__8__1 = new BTDMenuManager.__c__DisplayClass66_0(); __instance.__8__1.__4__this = __instance.__4__this; __instance.__8__1.previousMenu = __instance.__4__this.currMenu; @@ -40,11 +40,11 @@ static void Prefix(BTDMenuManager._OpenMenuInternal_d__52 __instance) { __instance.__4__this.currMenu = newCurrMenu; - __instance.__8__1._OpenMenuInternal_b__0(); + __instance.__8__1._OpenMenuInternal_b__0(); } } [HarmonyPostfix] - static void Postfix(BTDMenuManager._OpenMenuInternal_d__52 __instance) { + static void Postfix(BTDMenuManager._OpenMenuInternal_d__66 __instance) { bool isModdedMenu = false; ModMenuData mmd = null!; if (__instance.menuData != null) { diff --git a/Patch/MenuManager/MenuManager_UnloadSceneAsync.cs b/Patch/MenuManager/MenuManager_UnloadSceneAsync.cs index d6d1571..29cf7c6 100644 --- a/Patch/MenuManager/MenuManager_UnloadSceneAsync.cs +++ b/Patch/MenuManager/MenuManager_UnloadSceneAsync.cs @@ -4,10 +4,10 @@ namespace BTD6Rogue; -[HarmonyPatch(typeof(BTDMenuManager._UnloadSceneAsync_d__35), nameof(BTDMenuManager._UnloadSceneAsync_d__35.MoveNext))] +[HarmonyPatch(typeof(BTDMenuManager._UnloadSceneAsync_d__48), nameof(BTDMenuManager._UnloadSceneAsync_d__48.MoveNext))] static class MenuManager_UnloadSceneAsync { [HarmonyPrefix] - static void Prefix(BTDMenuManager._UnloadSceneAsync_d__35 __instance) { + static void Prefix(BTDMenuManager._UnloadSceneAsync_d__48 __instance) { if (__instance.sceneName.Contains("ModdedMenu") && __instance.__1__state == 0) { __instance.__4__this.sceneInstanceDict.Remove(__instance.sceneName); Scene scene = SceneManager.GetSceneByName(__instance.sceneName); diff --git a/Patch/SpawnChildren/SpawnChildren_CreatedChildren.cs b/Patch/SpawnChildren/SpawnChildren_CreatedChildren.cs index 6538d2d..8a1cad3 100644 --- a/Patch/SpawnChildren/SpawnChildren_CreatedChildren.cs +++ b/Patch/SpawnChildren/SpawnChildren_CreatedChildren.cs @@ -13,7 +13,7 @@ private static void Postfix(SpawnChildren __instance, List childernCreate if (__instance.bloon.emissionIndex >= 5000) { foreach (Bloon bloon in childernCreatedIn) { IncreaseBloonWorthModel.BloonWorthMutator bme = new IncreaseBloonWorthModel.BloonWorthMutator( - "CashlessBloon", 0, 0, ""); + "CashlessBloon", 0, 0, "", Il2Cpp.BloonProperties.None); bloon.AddMutator(bme, -1, false); } } diff --git a/Patch/Spawner/Spawner_Emit.cs b/Patch/Spawner/Spawner_Emit.cs index ef4385e..ad26642 100644 --- a/Patch/Spawner/Spawner_Emit.cs +++ b/Patch/Spawner/Spawner_Emit.cs @@ -1,49 +1,81 @@ -using HarmonyLib; -using Il2CppAssets.Scripts.Simulation.Track; +using BTD_Mod_Helper.Api; +using BTD_Mod_Helper.Extensions; +using HarmonyLib; +using Il2Cpp; +using Il2CppAssets.Scripts.Data.Gameplay.Mods; +using Il2CppAssets.Scripts.Data.Quests; using Il2CppAssets.Scripts.Models.Bloons; -using Il2CppAssets.Scripts.Simulation.Bloons; +using Il2CppAssets.Scripts.Models.Bloons.Behaviors; +using Il2CppAssets.Scripts.Models.Bloons.Behaviors.Actions; using Il2CppAssets.Scripts.Models.Towers.Projectiles.Behaviors; +using Il2CppAssets.Scripts.Simulation.Bloons; +using Il2CppAssets.Scripts.Simulation.Bloons.Behaviors; +using Il2CppAssets.Scripts.Simulation.Bloons.Behaviors.Actions; +using Il2CppAssets.Scripts.Simulation.Track; using System; +using System.Linq; namespace BTD6Rogue; [HarmonyPatch(typeof(Spawner), nameof(Spawner.Emit))] internal static class Spawner_Emit { - [HarmonyPrefix] - private static void Prefix(Spawner __instance, ref BloonModel bloonModel, int roundNumber, int emissionIndex) { + [HarmonyPrefix] + private static void Prefix(Spawner __instance, ref BloonModel bloonModel, int roundNumber, int emissionIndex) { if (BTD6Rogue.rogueGame is null) { return; } if (bloonModel.isBoss || bloonModel.baseId.Contains("Lych") || bloonModel.IsRock) { - BossUtil.GetBossFromBloonId(bloonModel.baseId).AdjustBloonModel(bloonModel, roundNumber / 20, false); - } - } + BossUtil.GetBossFromBloonId(bloonModel.baseId).AdjustBloonModel(bloonModel, roundNumber / 20, false); + } + } - [HarmonyPostfix] - private static void Postfix(Spawner __instance, BloonModel bloonModel, int roundNumber, int emissionIndex, ref Bloon __result) { - if (BTD6Rogue.rogueGame is not null) - { - if (bloonModel.isBoss || bloonModel.baseId.Contains("Lych") || bloonModel.IsRock) - { - RogueBoss boss = BossUtil.GetBossFromBloonId(bloonModel.baseId); - boss.AdjustBloon(__result, roundNumber / 20, false); - if (boss.IsBoss) - { - BTD6Rogue.rogueGame.roundManager.BossSpawned(); - } - } - - if (emissionIndex >= 5000) - { - IncreaseBloonWorthModel.BloonWorthMutator bme = new IncreaseBloonWorthModel.BloonWorthMutator( - "CashlessBloon", 0, 0, ""); - __result.AddMutator(bme, -1, false); - } - } - - if (bloonModel.isBoss) - { //Todo: maybe don't do the BTD6Rogue-Boss UI in non BTD6Rogue GameModes? + [HarmonyPostfix] + private static void Postfix(Spawner __instance, BloonModel bloonModel, int roundNumber, int emissionIndex, ref Bloon __result) + { + if (BTD6Rogue.rogueGame is null) { return; } + if (bloonModel.isBoss || bloonModel.baseId.Contains("Lych") || bloonModel.IsRock) + { + RogueBoss boss = BossUtil.GetBossFromBloonId(bloonModel.baseId); + boss.AdjustBloon(__result, roundNumber / 20, false); + if (boss.IsBoss) + { + BTD6Rogue.rogueGame.roundManager.BossSpawned(); + } + } + if (emissionIndex >= 5000) + { + IncreaseBloonWorthModel.BloonWorthMutator bme = new IncreaseBloonWorthModel.BloonWorthMutator( + "CashlessBloon", 0, 0, "", Il2Cpp.BloonProperties.None); + __result.AddMutator(bme, -1, false); + } + if (bloonModel.isBoss) + { __instance.bossBloonManager.currentBoss = __result; __instance.bossBloonManager.currentBossTier = Math.Min(((roundNumber + 1) / 20), 5); - } + } + //custom properties here + /*var rand = new Random(); + bool isTattered = false; + //if (roundNumber >= 8 && !bloonModel.isMoab) { isTattered = rand.Next(4) == 0; } + if (roundNumber >= 8 && BTD6Rogue.rogueGame.modifiers.Any(m => m is ZNewPropertiesModifier) && !bloonModel.isMoab) { isTattered = rand.Next(4) == 0; } + if (isTattered) + { + __result.AddMutatorForNumLayers(new BuffBloonSpeedModel.BloonBuffMutator(2, "Bleed"), layerCount: 1); + }*/ + + /*bool isSplitting = false; + if (roundNumber >= 6 && !bloonModel.isMoab && BTD6Rogue.rogueGame.modifiers.Any(m => m is ZNewPropertiesModifier) && bloonModel.bloonProperties == BloonProperties.None) { isSplitting = rand.Next(4) == 0; } + if (BTD6Rogue.rogueGame.modifiers.Any(m => m is OForceSplittingModifier) && !bloonModel.isMoab) { isSplitting = true } + if (isSplitting) + { + __result.bloonModel.RemoveAllChildren(); + __result.bloonModel.AddToChildren(__result.bloonModel.id, 3); + }*/ - } + bool isLead = false; + //if (roundNumber >= 28 && !bloonModel.isMoab && BTD6Rogue.rogueGame.modifiers.Any(m => m is ZNewPropertiesModifier)) { isLead = rand.Next(4) == 0; } + //if (ModifierUtil.HasModifier() && !bloonModel.isMoab) { isLead = true; } + if (isLead) + { + __result.bloonModel.bloonProperties |= Il2Cpp.BloonProperties.Lead; + } + } } diff --git a/Patch/TowerSelectionMenu/TowerSelectionMenu_IsUpgradePathClosed.cs b/Patch/TowerSelectionMenu/TowerSelectionMenu_IsUpgradePathClosed.cs index 4361831..2d16791 100644 --- a/Patch/TowerSelectionMenu/TowerSelectionMenu_IsUpgradePathClosed.cs +++ b/Patch/TowerSelectionMenu/TowerSelectionMenu_IsUpgradePathClosed.cs @@ -1,8 +1,15 @@ -using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu; +using BTD_Mod_Helper.Api.Hooks; +using BTD_Mod_Helper.Api.Hooks.BloonHooks; +using BTD_Mod_Helper.Extensions; using HarmonyLib; -using Il2CppAssets.Scripts.Unity.UI_New.InGame; +using Il2CppAssets.Scripts.Simulation.Bloons; using Il2CppAssets.Scripts.Simulation.Towers; -using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Unity.UI_New.InGame; +using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu; +using Il2CppInterop.Runtime; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; namespace BTD6Rogue; diff --git a/Patch/UpgradeObject/UpgradeObject_UpdateVisuals.cs b/Patch/UpgradeObject/UpgradeObject_UpdateVisuals.cs index 4b265b5..6ca5a44 100644 --- a/Patch/UpgradeObject/UpgradeObject_UpdateVisuals.cs +++ b/Patch/UpgradeObject/UpgradeObject_UpdateVisuals.cs @@ -14,7 +14,7 @@ private static bool Prefix(UpgradeObject __instance, int path, bool upgradeClick var maxTierRestricted = __instance.CheckRestrictedPath(); __instance.SetTier(__instance.tier, maxTier, maxTierRestricted); __instance.currentUpgrade.UpdateVisuals(); - __instance.upgradeButton.UpdateVisuals(path, upgradeClicked); + __instance.upgradeButton.UpdateVisuals(path, __instance.tier, upgradeClicked); return false; } } \ No newline at end of file diff --git a/Resources/Buttons/FallbackPortrait/TowerContainerNeutral.png b/Resources/Buttons/FallbackPortrait/TowerContainerNeutral.png new file mode 100644 index 0000000..320ab14 Binary files /dev/null and b/Resources/Buttons/FallbackPortrait/TowerContainerNeutral.png differ diff --git a/Resources/Buttons/FallbackPortrait/TowerContainerPower.png b/Resources/Buttons/FallbackPortrait/TowerContainerPower.png new file mode 100644 index 0000000..315ceb5 Binary files /dev/null and b/Resources/Buttons/FallbackPortrait/TowerContainerPower.png differ diff --git a/Resources/Buttons/UnknownHeroPortrait.png b/Resources/Buttons/FallbackPortrait/UnknownHeroPortrait.png similarity index 100% rename from Resources/Buttons/UnknownHeroPortrait.png rename to Resources/Buttons/FallbackPortrait/UnknownHeroPortrait.png diff --git a/Resources/Buttons/UnknownParagonPortrait.png b/Resources/Buttons/FallbackPortrait/UnknownParagonPortrait.png similarity index 100% rename from Resources/Buttons/UnknownParagonPortrait.png rename to Resources/Buttons/FallbackPortrait/UnknownParagonPortrait.png diff --git a/Resources/Buttons/FallbackPortrait/UnknownPowerPortrait.png b/Resources/Buttons/FallbackPortrait/UnknownPowerPortrait.png new file mode 100644 index 0000000..919c233 Binary files /dev/null and b/Resources/Buttons/FallbackPortrait/UnknownPowerPortrait.png differ diff --git a/Resources/Buttons/FallbackPortrait/UnknownSubTowerPortrait.png b/Resources/Buttons/FallbackPortrait/UnknownSubTowerPortrait.png new file mode 100644 index 0000000..2c72534 Binary files /dev/null and b/Resources/Buttons/FallbackPortrait/UnknownSubTowerPortrait.png differ diff --git a/Resources/Buttons/UnknownTowerPortrait.png b/Resources/Buttons/FallbackPortrait/UnknownTowerPortrait.png similarity index 100% rename from Resources/Buttons/UnknownTowerPortrait.png rename to Resources/Buttons/FallbackPortrait/UnknownTowerPortrait.png diff --git a/Resources/Buttons/UnknownTowerPortrait.xcf b/Resources/Buttons/FallbackPortrait/UnknownTowerPortrait.xcf similarity index 63% rename from Resources/Buttons/UnknownTowerPortrait.xcf rename to Resources/Buttons/FallbackPortrait/UnknownTowerPortrait.xcf index 6f21bda..b58578a 100644 Binary files a/Resources/Buttons/UnknownTowerPortrait.xcf and b/Resources/Buttons/FallbackPortrait/UnknownTowerPortrait.xcf differ diff --git a/Round/RoundManager.cs b/Round/RoundManager.cs index cbfe282..f77da87 100644 --- a/Round/RoundManager.cs +++ b/Round/RoundManager.cs @@ -2,6 +2,7 @@ using BTD_Mod_Helper.Extensions; using Il2CppAssets.Scripts.Models.Rounds; using Il2CppAssets.Scripts.Unity.UI_New.InGame; +using Il2CppAssets.Scripts.Unity.UI_New.Popups; using System; using System.Collections.Generic; using System.Threading; @@ -15,8 +16,10 @@ public class RoundManager(InGame game) { public string nextBoss = ""; public bool activeBoss = false; + public Thread? cashlessThread = null; + public bool? isCashless = null; - public int randMincrease = 400; + public int randMincrease = 400; public int minIncrease = 600; private int previousSpawn = 0; @@ -24,19 +27,43 @@ public class RoundManager(InGame game) { public void BossSpawned() { activeBoss = true; previousSpawn = 5000; // MS until start spawning cashless bloons - Thread t = new Thread(new ThreadStart(TrySpawnCashlessBloons)); - t.Start(); - } - - public void TrySpawnCashlessBloons() { - int round = game.bridge.GetCurrentRound(); - while (activeBoss) { - Thread.Sleep(previousSpawn); - if (!activeBoss) { break; } // check if active boss got changed during Thread.Sleep - if (game == null || game.bridge == null) { break; } - if (round != game.bridge.GetCurrentRound()) { break; } - if (BTD6Rogue.rogueGame == null) { break; } - int groupRbe = GetRoundRbe(round) / 15; + cashlessThread = new Thread(new ThreadStart(TrySpawnCashlessBloons)); + cashlessThread.Start(); + } + + [Obsolete("This doesn't help/work.")] + public void KillCashlessBloonsThread() + { + if (BTD6Rogue.rogueGame == null) { return; } + if (BTD6Rogue.rogueGame.roundManager == null) { return; } + Thread? thread = BTD6Rogue.rogueGame.roundManager.cashlessThread; + if (thread != null && thread.IsAlive) + { + BTD6Rogue.rogueGame.roundManager.activeBoss = false; + if (!thread.Join(5000)) { BTD6Rogue.LogMessage("cashlessThread did not shut down in time. It may cause a crash next time a boss spawns.", "RoundManager.KillCashlessBloonsThread", ErrorLevels.Critical); } + } + //BTD6Rogue.rogueGame.roundManager.cashlessThread = null; + } + + public void TrySpawnCashlessBloons() { + while (activeBoss) + { + //game = InGame.instance; + Thread.Sleep(previousSpawn); + ///I FUCKING HATE THIS BUG HHHH + //if (!IsBridgeSafe()) { break; } //this just causes more proplums + //if (!IsBridgeSafe()) { game = InGame.instance; } //this just causes more proplums + /*if (!IsBridgeSafe()) //TODO: dispose of RoundManager when we restart the run + { + BTD6Rogue.LogMessage("TrySpawnCashlessBloons Thread is using a stale InGame instance. It WILL cause a crash next time a boss spawns.", "RoundManager.TrySpawnCashlessBloons", ErrorLevels.Critical); + throw new AccessViolationException("TrySpawnCashlessBloons Thread is using a stale InGame instance. It WILL cause a FATAL AccessViolationException next time a boss spawns."); + //break; + }*/ + if (!activeBoss) { break; } // check if active boss got changed during Thread.Sleep + if (game == null || game.bridge == null) { break; } + if (BTD6Rogue.rogueGame == null) { break; } + int round = game.bridge.GetCurrentRound(); + int groupRbe = GetRoundRbe(round) / 15; RogueDifficulty difficulty = BTD6Rogue.rogueGame.difficulty; List>> sendableBloons = difficulty.GetSendableRogueBloons(round + 1, groupRbe); if (sendableBloons.Count < 1) { continue; } @@ -45,18 +72,34 @@ public void TrySpawnCashlessBloons() { bool isCamo = false; bool isRegrow = false; bool isFortified = false; - if (bloonData.Item2.Contains("Camo")) { isCamo = new Random().Next(4) == 0; } - if (bloonData.Item2.Contains("Regrow")) { isRegrow = new Random().Next(4) == 0; } - if (bloonData.Item2.Contains("Fortified")) { isFortified = new Random().Next(4) == 0; } + if (bloonData.Item2.Contains("Camo")) { isCamo = new Random().Next(4) == 0 || bloonData.Item1.ForceCamo || ModifierUtil.HasModifier(); } + if (bloonData.Item2.Contains("Regrow")) { isRegrow = new Random().Next(4) == 0 || bloonData.Item1.ForceRegrow || ModifierUtil.HasModifier(); } + if (bloonData.Item2.Contains("Fortified")) { isFortified = new Random().Next(4) == 0 || bloonData.Item1.ForceFortified /*|| ModifierUtil.HasModifier()*/; } int nextIncrease = 0 + new Random().Next(600) + 200; BloonGroupModel bgm = bloonData.Item1.GenerateBloonGroup(round, groupRbe, 0, nextIncrease, isCamo, isRegrow, isFortified); game.bridge.SpawnBloons(bgm.GetEmissions(), round, 5000); previousSpawn = nextIncrease * 3; // Change previous spawn timer based off the bloon group spawned just now } - } - - public void BossDefeated() { + } + + public bool IsBridgeSafe() + { + try + { + var bridge = game?.bridge; + if (bridge == null) return false; + int round = bridge.GetCurrentRound(); + return true; + } + catch + { + return false; + } + } + + + public void BossDefeated() { activeBoss = false; } @@ -142,11 +185,11 @@ private RoundModel GenerateRoundModel(RoundModel baseRoundModel, int round) { bool isRegrow = false; bool isFortified = false; - if (bloonData.Item2.Contains("Camo")) { isCamo = new Random().Next(4) == 0; } - if (bloonData.Item2.Contains("Regrow")) { isRegrow = new Random().Next(4) == 0; } - if (bloonData.Item2.Contains("Fortified")) { isFortified = new Random().Next(4) == 0; } + if (bloonData.Item2.Contains("Camo")) { isCamo = new Random().Next(4) == 0 || bloonData.Item1.ForceCamo || ModifierUtil.HasModifier(); } + if (bloonData.Item2.Contains("Regrow")) { isRegrow = new Random().Next(4) == 0 || bloonData.Item1.ForceRegrow || ModifierUtil.HasModifier(); } + if (bloonData.Item2.Contains("Fortified")) { isFortified = new Random().Next(4) == 0 || bloonData.Item1.ForceFortified /*|| ModifierUtil.HasModifier()*/; } - bloonGroupModels.Add(bloonData.Item1.GenerateBloonGroup(round, groupRbe, mincrease, nextIncrease, isCamo, isRegrow, isFortified)); + bloonGroupModels.Add(bloonData.Item1.GenerateBloonGroup(round, groupRbe, mincrease, nextIncrease, isCamo, isRegrow, isFortified)); int generatedGroupAmount = bloonData.Item1.GetBloonAmount(round, groupRbe, isFortified); int generatedGroupRbe = bloonData.Item1.GetGroupRbe(round, generatedGroupAmount, isFortified); remainingRbe -= generatedGroupRbe; diff --git a/Settings/RogueModSettings.cs b/Settings/RogueModSettings.cs index f767113..5520293 100644 --- a/Settings/RogueModSettings.cs +++ b/Settings/RogueModSettings.cs @@ -1,19 +1,21 @@ -using BTD_Mod_Helper.Api.Data; +using BTD_Mod_Helper; +using BTD_Mod_Helper.Api.Data; using BTD_Mod_Helper.Api.ModOptions; using BTD_Mod_Helper.Extensions; using Il2CppAssets.Scripts.Unity.UI_New.Popups; +using System; namespace BTD6Rogue; public class RogueModSettings : ModSettings { - public static readonly ModSettingCategory LoggingSettings = new("Logging Settings"); + public static readonly ModSettingCategory LoggingSettings = new("Logging Settings"); - public static readonly ModSettingBool LogInfoMessages = new(true) { category = LoggingSettings }; - public static readonly ModSettingBool LogWarningMessages = new(true) { category = LoggingSettings }; - public static readonly ModSettingBool LogErrorMessages = new(true) { category = LoggingSettings }; - public static readonly ModSettingBool LogCriticalMessages = new(true) { category = LoggingSettings }; - public static readonly ModSettingBool LogDebugMessages = new(false) { category = LoggingSettings }; + public static readonly ModSettingBool LogInfoMessages = new(true) { category = LoggingSettings }; + public static readonly ModSettingBool LogWarningMessages = new(true) { category = LoggingSettings }; + public static readonly ModSettingBool LogErrorMessages = new(true) { category = LoggingSettings }; + public static readonly ModSettingBool LogCriticalMessages = new(true) { category = LoggingSettings }; + public static readonly ModSettingBool LogDebugMessages = new(false) { category = LoggingSettings }; private static readonly ModSettingButton BloonValidationButton = new() @@ -23,12 +25,18 @@ public class RogueModSettings : ModSettings { "Validates each RogueBloon to ensure it references existing Bloons in the GameModel. Logs warnings if invalid references are found. This is unnecessary if no new RogueBloons are being added by external mods.", action = () => { - BloonValidation v = new(); - v.ValidateAllRogueBloons(); + BloonUtil.GetAllBloons(); PopupScreen.instance.SafelyQueue(screen => screen.ShowOkPopup($"Finished validating RogueBloons. Check the logs for details.")); }, buttonText = "Validate", category = "Modding" }; + + public static readonly ModSettingCategory PowerSettings = new("Logging Settings") { collapsed = !ModHelper.HasMod("Powers-In-Shop") }; + public enum AllowPowersEnum { None, Standard, Unlimited } + + public static readonly ModSettingEnum AllowPowersInShop = new(AllowPowersEnum.None) { category = "Powers", description = "Requires Powers In Shop\nSets if Powers are removed from the shop in BTD Rogue modes.\nNone: No Powers appear in the shop.\nStandard: Start with Unlimited Banana Farmers and Tech Bots.\nUnlimited: Start with Unlimited copies of every Power.\nThe \"No Powers\" modifier takes precedent over this option. If the AllowProPowersAsMonkeys setting is on, it prevents this oppton from applying to Powers Pro." }; + //public static readonly ModSettingBool AllowBattleCatInMonkeyChoices = new(false) { category = "Powers" }; + public static readonly ModSettingBool AllowProPowersAsMonkeys = new(false) { category = "Powers", description = "Requires Powers In Shop\nPowers Pro can appear as Monkeys in Tower Choices/Selections.\nPowers Pro start with all upgrades locked, with their tier 1/2/3 upgrades being available alongside Monkeys' tier 3/4/5 upgrades. \n**You have to unlock Powers Pro and their upgrades normally to be able to buy them from the shop!**\nThe \"No Powers\" modifier takes precedent over this option." }; } diff --git a/Settings/ValdateBloon.cs b/Settings/ValdateBloon.cs index f34f9d3..c1f8f3d 100644 --- a/Settings/ValdateBloon.cs +++ b/Settings/ValdateBloon.cs @@ -1,47 +1,25 @@ using Il2CppAssets.Scripts.Unity; +using System; namespace BTD6Rogue { - public class BloonValidation + [Obsolete("Bloon Validation has been moved to BloonUtil.")] + public static class BloonValidation { - public void ValidateRogueBloon(RogueBloon bloon) + [Obsolete("Moved to BloonUtil.")] + public static void ValidateRogueBloon(RogueBloon bloon) { - string?[] arr = [bloon.BaseBloonId, null, null, null, null, null, null, null]; // - string[] brr = ["", "Camo", "Fortified", "FortifiedCamo", "Regrow", "RegrowCamo", "RegrowFortified", "RegrowFortifiedCamo"]; //Suffixes - - if (bloon.Camo) { arr[1] = bloon.BaseBloonId + brr[1]; } - if (bloon.Fortified) { arr[2] = bloon.BaseBloonId + brr[2]; } - if (bloon.Camo && bloon.Fortified) { arr[3] = bloon.BaseBloonId + brr[3]; } - if (bloon.Regrow) { arr[4] = bloon.BaseBloonId + brr[4]; } - if (bloon.Regrow && bloon.Camo) { arr[5] = bloon.BaseBloonId + brr[5]; } - if (bloon.Regrow && bloon.Fortified) { arr[6] = bloon.BaseBloonId + brr[6]; } - if (bloon.Regrow && bloon.Fortified && bloon.Camo) { arr[7] = bloon.BaseBloonId + brr[7]; } - - foreach (var j in arr) //Nullable string array - { - if (j is null) { continue; } - bool found = false; - foreach (var i in Game.instance.model.bloons) // Il2CppReferenceArray - { - if (i.id == j) - { - found = true; - break; // Exit loop when a match is found - } - } - if (!found) - { - BTD6Rogue.LogMessage($"The {j} Bloon was not found. It may cause a crash ingame.", this, ErrorLevels.Warning); - } - } + BloonUtil.ValidateRogueBloon(bloon); } - public void ValidateAllRogueBloons() + [Obsolete ("BloonUtil.GetAllBloons() now validates each RogueBloon.")] + public static void ValidateAllRogueBloons() { - foreach (var rogueBloon in BloonUtil.GetAllBloons()) + BloonUtil.GetAllBloons(); + /*foreach (var rogueBloon in BloonUtil.GetAllBloons()) { ValidateRogueBloon(rogueBloon); - } + }*/ } } } diff --git a/Tower/Hero/HeroData.cs b/Towers/Hero/HeroData.cs similarity index 100% rename from Tower/Hero/HeroData.cs rename to Towers/Hero/HeroData.cs diff --git a/Tower/Hero/HeroUtil.cs b/Towers/Hero/HeroUtil.cs similarity index 74% rename from Tower/Hero/HeroUtil.cs rename to Towers/Hero/HeroUtil.cs index 1039c58..cdb5028 100644 --- a/Tower/Hero/HeroUtil.cs +++ b/Towers/Hero/HeroUtil.cs @@ -12,12 +12,12 @@ public static List GetEnabledRogueHeroes(RogueGame game) { foreach (RogueHero tower in ModContent.GetContent()) { if (tower.GetBaseHero() is null) { - BTD6Rogue.LogMessage("The RogueHero " + tower.Name + "'s BaseHeroId (" + tower.BaseHeroId + ") returns a null tower. They have been disabled.", tower, ErrorLevels.Error); + BTD6Rogue.LogMessage("The RogueHero " + tower.Name + "'s BaseHeroId (" + tower.BaseHeroId + ") returns a null tower. They have been disabled.", tower, ErrorLevels.Debug); continue; } - if (tower.GetBaseHero().towerSet != Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Hero) + if (tower.GetBaseHero().towerSet != Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Hero && tower.GetBaseHero().upgrades != new Il2CppInterop.Runtime.InteropTypes.Arrays.Il2CppReferenceArray([])) { - BTD6Rogue.LogMessage("The RogueTower " + tower.Name + "'s BaseTowerId (" + tower.BaseHeroId + ") returns a tower outside of the Hero TowerSet. This may cause issues.", tower, ErrorLevels.Warning); + BTD6Rogue.LogMessage("The RogueHero " + tower.Name + "'s BaseTowerId (" + tower.BaseHeroId + ") returns a tower outside of the Hero TowerSet. This may cause issues.", tower, ErrorLevels.Warning); } if (game.towerManager.disabledTowerSets.Contains(Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Hero)) { continue; @@ -38,7 +38,8 @@ public static HeroChoice[] GetHeroesChoiceData(RogueGame game) { List rogueHeroes = GetEnabledRogueHeroes(game); foreach (RogueHero rogueHero in rogueHeroes) { - heroChoices.Add(CreateHeroChoiceData(rogueHero)); + if (rogueHero.ChoiceBlacklisted) { continue; } + heroChoices.Add(CreateHeroChoiceData(rogueHero)); } return heroChoices.ToArray(); @@ -72,11 +73,11 @@ public static HeroChoice[] CreateValidHeroChoices(RogueGame rogueGame) { List heroes = new List(); List possibleChoices = CreateAllValidHeroChoices(rogueGame); - if (possibleChoices.Count < 3) { return null!; } + if (possibleChoices.Count < 3 || (possibleChoices.Count < 2 && ModifierUtil.HasModifier())) { return null!; } - while (heroes.Count < 3) { + while (heroes.Count < 3 || (heroes.Count < 2 && ModifierUtil.HasModifier())) { HeroChoice towerChoice = possibleChoices[new Random().Next(possibleChoices.Count)]; - if (heroes.Contains(towerChoice)) { continue; } + if (heroes.Contains(towerChoice) || towerChoice.rogueTower.ChoiceBlacklisted) { continue; } heroes.Add(towerChoice); } diff --git a/Towers/Hero/ModdedHeroes/Asmodeus.cs b/Towers/Hero/ModdedHeroes/Asmodeus.cs new file mode 100644 index 0000000..e018950 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Asmodeus.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Asmodeus : RogueHero { + public override string BaseHeroId => "Asmodeus-AsmodeusHero"; +} diff --git a/Towers/Hero/ModdedHeroes/BannerMonkey.cs b/Towers/Hero/ModdedHeroes/BannerMonkey.cs new file mode 100644 index 0000000..560c0dc --- /dev/null +++ b/Towers/Hero/ModdedHeroes/BannerMonkey.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class BannerMonkey : RogueHero { + public override string BaseHeroId => "BannerMonkeyHero-bbb"; +} diff --git a/Towers/Hero/ModdedHeroes/Bonnie.cs b/Towers/Hero/ModdedHeroes/Bonnie.cs new file mode 100644 index 0000000..6e63c9a --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Bonnie.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Bonnie : RogueHero { + public override string BaseHeroId => "BonnieHeroMod-BonnieHero"; +} diff --git a/Towers/Hero/ModdedHeroes/DinoDirk.cs b/Towers/Hero/ModdedHeroes/DinoDirk.cs new file mode 100644 index 0000000..b80a831 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/DinoDirk.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class DinoDirk : RogueHero { + public override string BaseHeroId => "DirkTheDino-DinoDirk"; +} diff --git a/Towers/Hero/ModdedHeroes/Frankenstein.cs b/Towers/Hero/ModdedHeroes/Frankenstein.cs new file mode 100644 index 0000000..257ec87 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Frankenstein.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Frankenstein : RogueHero { + public override string BaseHeroId => "FrankensteinHero-FrankensteinHero"; +} diff --git a/Towers/Hero/ModdedHeroes/IndustrialFarmer.cs b/Towers/Hero/ModdedHeroes/IndustrialFarmer.cs new file mode 100644 index 0000000..2e38d41 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/IndustrialFarmer.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class IndustrialFarmer : RogueHero { + public override string BaseHeroId => "IndustrialFarmer-IndustrialFarmer"; +} diff --git a/Towers/Hero/ModdedHeroes/Kairo.cs b/Towers/Hero/ModdedHeroes/Kairo.cs new file mode 100644 index 0000000..ef1e778 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Kairo.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Kairo : RogueHero { + public override string BaseHeroId => "Kairo-KairoHero"; +} diff --git a/Towers/Hero/ModdedHeroes/Lynn.cs b/Towers/Hero/ModdedHeroes/Lynn.cs new file mode 100644 index 0000000..970b908 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Lynn.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Lynn : RogueHero { + public override string BaseHeroId => "EngineerHero-LynnHero"; +} diff --git a/Towers/Hero/ModdedHeroes/Osiris.cs b/Towers/Hero/ModdedHeroes/Osiris.cs new file mode 100644 index 0000000..1dfa3e9 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Osiris.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Osiris : RogueHero { + public override string BaseHeroId => "OsirisHero-OsirisHero"; +} diff --git a/Towers/Hero/ModdedHeroes/PlagueDoctor.cs b/Towers/Hero/ModdedHeroes/PlagueDoctor.cs new file mode 100644 index 0000000..282a655 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/PlagueDoctor.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class PlagueDoctor : RogueHero { + public override string BaseHeroId => "Halloween2025-PlagueDoctor"; +} diff --git a/Towers/Hero/ModdedHeroes/REX.cs b/Towers/Hero/ModdedHeroes/REX.cs new file mode 100644 index 0000000..d0594f1 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/REX.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class REX : RogueHero { + public override string BaseHeroId => "REXHero-REXTower"; +} diff --git a/Towers/Hero/ModdedHeroes/Sally.cs b/Towers/Hero/ModdedHeroes/Sally.cs new file mode 100644 index 0000000..17db192 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Sally.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Sally : RogueHero { + public override string BaseHeroId => "SallyPokehellHero-Sally"; +} diff --git a/Towers/Hero/ModdedHeroes/Telekinetic.cs b/Towers/Hero/ModdedHeroes/Telekinetic.cs new file mode 100644 index 0000000..b5eab44 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Telekinetic.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Telekinetic : RogueHero { + public override string BaseHeroId => "Template-Telekinetic"; //Ozrath +} diff --git a/Towers/Hero/ModdedHeroes/TimeHero.cs b/Towers/Hero/ModdedHeroes/TimeHero.cs new file mode 100644 index 0000000..a26a1b9 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/TimeHero.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class TimeHero : RogueHero { + public override string BaseHeroId => "TowerHero-TimeHero"; //Mae +} diff --git a/Towers/Hero/ModdedHeroes/Wendell.cs b/Towers/Hero/ModdedHeroes/Wendell.cs new file mode 100644 index 0000000..cbf501c --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Wendell.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Wendell : RogueHero { + public override string BaseHeroId => "HeliumHelper-Wendell"; +} diff --git a/Towers/Hero/ModdedHeroes/Zagara.cs b/Towers/Hero/ModdedHeroes/Zagara.cs new file mode 100644 index 0000000..be51f84 --- /dev/null +++ b/Towers/Hero/ModdedHeroes/Zagara.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Zagara : RogueHero { + public override string BaseHeroId => "Zagara"; +} diff --git a/Tower/Hero/RogueHero.cs b/Towers/Hero/RogueHero.cs similarity index 72% rename from Tower/Hero/RogueHero.cs rename to Towers/Hero/RogueHero.cs index 854e279..7aacd52 100644 --- a/Tower/Hero/RogueHero.cs +++ b/Towers/Hero/RogueHero.cs @@ -6,10 +6,10 @@ namespace BTD6Rogue; public abstract class RogueHero : NamedModContent { public abstract string BaseHeroId { get; } - - public virtual TowerModel GetBaseHero() { + public virtual bool ChoiceBlacklisted => false; + public virtual bool SelectBlacklisted => false; + public virtual TowerModel GetBaseHero() { return Game.instance.model.GetTowerFromId(BaseHeroId); - //return Game.instance.model.GetHeroWithNameAndLevel(BaseHeroId, 1); } diff --git a/Tower/Hero/VanillaHeroes/AdmiralBrickell.cs b/Towers/Hero/VanillaHeroes/AdmiralBrickell.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/AdmiralBrickell.cs rename to Towers/Hero/VanillaHeroes/AdmiralBrickell.cs diff --git a/Tower/Hero/VanillaHeroes/Adora.cs b/Towers/Hero/VanillaHeroes/Adora.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Adora.cs rename to Towers/Hero/VanillaHeroes/Adora.cs diff --git a/Tower/Hero/VanillaHeroes/Benjamin.cs b/Towers/Hero/VanillaHeroes/Benjamin.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Benjamin.cs rename to Towers/Hero/VanillaHeroes/Benjamin.cs diff --git a/Tower/Hero/VanillaHeroes/CaptainChurchill.cs b/Towers/Hero/VanillaHeroes/CaptainChurchill.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/CaptainChurchill.cs rename to Towers/Hero/VanillaHeroes/CaptainChurchill.cs diff --git a/Tower/Hero/VanillaHeroes/Corvus.cs b/Towers/Hero/VanillaHeroes/Corvus.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Corvus.cs rename to Towers/Hero/VanillaHeroes/Corvus.cs diff --git a/Tower/Hero/VanillaHeroes/Etienne.cs b/Towers/Hero/VanillaHeroes/Etienne.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Etienne.cs rename to Towers/Hero/VanillaHeroes/Etienne.cs diff --git a/Tower/Hero/VanillaHeroes/Ezili.cs b/Towers/Hero/VanillaHeroes/Ezili.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Ezili.cs rename to Towers/Hero/VanillaHeroes/Ezili.cs diff --git a/Tower/Hero/VanillaHeroes/Geraldo.cs b/Towers/Hero/VanillaHeroes/Geraldo.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Geraldo.cs rename to Towers/Hero/VanillaHeroes/Geraldo.cs diff --git a/Tower/Hero/VanillaHeroes/Gwendolin.cs b/Towers/Hero/VanillaHeroes/Gwendolin.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Gwendolin.cs rename to Towers/Hero/VanillaHeroes/Gwendolin.cs diff --git a/Tower/Hero/VanillaHeroes/ObynGreenfoot.cs b/Towers/Hero/VanillaHeroes/ObynGreenfoot.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/ObynGreenfoot.cs rename to Towers/Hero/VanillaHeroes/ObynGreenfoot.cs diff --git a/Tower/Hero/VanillaHeroes/PatFusty.cs b/Towers/Hero/VanillaHeroes/PatFusty.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/PatFusty.cs rename to Towers/Hero/VanillaHeroes/PatFusty.cs diff --git a/Tower/Hero/VanillaHeroes/Psi.cs b/Towers/Hero/VanillaHeroes/Psi.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Psi.cs rename to Towers/Hero/VanillaHeroes/Psi.cs diff --git a/Tower/Hero/VanillaHeroes/Quincy.cs b/Towers/Hero/VanillaHeroes/Quincy.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Quincy.cs rename to Towers/Hero/VanillaHeroes/Quincy.cs diff --git a/Tower/Hero/VanillaHeroes/Rosalia.cs b/Towers/Hero/VanillaHeroes/Rosalia.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Rosalia.cs rename to Towers/Hero/VanillaHeroes/Rosalia.cs diff --git a/Tower/Hero/VanillaHeroes/Sauda.cs b/Towers/Hero/VanillaHeroes/Sauda.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/Sauda.cs rename to Towers/Hero/VanillaHeroes/Sauda.cs diff --git a/Towers/Hero/VanillaHeroes/Silas.cs b/Towers/Hero/VanillaHeroes/Silas.cs new file mode 100644 index 0000000..fee30a3 --- /dev/null +++ b/Towers/Hero/VanillaHeroes/Silas.cs @@ -0,0 +1,7 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class Silas : RogueHero { + public override string BaseHeroId => "Silas"; +} diff --git a/Tower/Hero/VanillaHeroes/StrikerJones.cs b/Towers/Hero/VanillaHeroes/StrikerJones.cs similarity index 100% rename from Tower/Hero/VanillaHeroes/StrikerJones.cs rename to Towers/Hero/VanillaHeroes/StrikerJones.cs diff --git a/Towers/Modded/ArmyBase.cs b/Towers/Modded/ArmyBase.cs new file mode 100644 index 0000000..c487aa3 --- /dev/null +++ b/Towers/Modded/ArmyBase.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class ArmyBase : RogueTower +{ + public override string BaseTowerId => "armybase-ArmyBase"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/BakerMonkey.cs b/Towers/Modded/BakerMonkey.cs new file mode 100644 index 0000000..a4b459e --- /dev/null +++ b/Towers/Modded/BakerMonkey.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class BakerMonkeyV1 : RogueTower +{ + public override string BaseTowerId => "BakerMonkeyMod-BakerMonkey"; //Same ID for both TowerMakingGroup's and Stiefanek's Version + + public override Dictionary TowerTags => []; + + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} +public class BakerMonkeyV2 : RogueTower +{ + public override string BaseTowerId => "BakerMonkeyModV2-BakerMonkey"; + + public override Dictionary TowerTags => []; + + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/BananaFarmerTower.cs b/Towers/Modded/BananaFarmerTower.cs new file mode 100644 index 0000000..521068b --- /dev/null +++ b/Towers/Modded/BananaFarmerTower.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class BananaFarmerTower : RogueTower +{ + public override string BaseTowerId => "BananaFarmerMod-BananaFarmerTower"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 1)]; +} \ No newline at end of file diff --git a/Towers/Modded/BoxerMonkey.cs b/Towers/Modded/BoxerMonkey.cs new file mode 100644 index 0000000..a3f2972 --- /dev/null +++ b/Towers/Modded/BoxerMonkey.cs @@ -0,0 +1,11 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class BoxerMonkey : RogueTower { + public override string BaseTowerId => "boxermonkey-exampul1"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 4), new(1, 4), new(1, 4)]; +} \ No newline at end of file diff --git a/Towers/Modded/CardMonkey.cs b/Towers/Modded/CardMonkey.cs new file mode 100644 index 0000000..1984fc3 --- /dev/null +++ b/Towers/Modded/CardMonkey.cs @@ -0,0 +1,13 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class CardMonkey : RogueTower { + public override string BaseTowerId => "CardMonkey-CardMonkey"; + + public override Dictionary TowerTags => []; + + public override Vector2Int[] TowerAmountRanges => [new(1, 4), new(1, 4), new(1, 4)]; +} \ No newline at end of file diff --git a/Towers/Modded/CaveMonkeyTower.cs b/Towers/Modded/CaveMonkeyTower.cs new file mode 100644 index 0000000..4268098 --- /dev/null +++ b/Towers/Modded/CaveMonkeyTower.cs @@ -0,0 +1,11 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class CaveMonkeyTower : RogueTower { + public override string BaseTowerId => "CaveMonkeyV2-CaveMonkey"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 1), new(1, 4)]; +} \ No newline at end of file diff --git a/Towers/Modded/CyberMonkey.cs b/Towers/Modded/CyberMonkey.cs new file mode 100644 index 0000000..f2a2151 --- /dev/null +++ b/Towers/Modded/CyberMonkey.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class CyberMonkey : RogueTower +{ + public override string BaseTowerId => "DarksTowers-CyberMonkey"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/GhostMonkey.cs b/Towers/Modded/GhostMonkey.cs new file mode 100644 index 0000000..248cf1e --- /dev/null +++ b/Towers/Modded/GhostMonkey.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class GhostMonkey : RogueTower +{ + public override string BaseTowerId => "Halloween2025-GhostMonkey"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/MonkeyMachine.cs b/Towers/Modded/MonkeyMachine.cs new file mode 100644 index 0000000..632e0e1 --- /dev/null +++ b/Towers/Modded/MonkeyMachine.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class MonkeyMachine : RogueTower +{ + public override string BaseTowerId => "MonkeyMachine-Monkeymachine"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/MonkeyOfLight.cs b/Towers/Modded/MonkeyOfLight.cs new file mode 100644 index 0000000..22eeb7d --- /dev/null +++ b/Towers/Modded/MonkeyOfLight.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class MonkeyofLight : RogueTower +{ + public override string BaseTowerId => "DarksTowers-MonkeyofLight"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/Omitions.md b/Towers/Modded/Omitions.md new file mode 100644 index 0000000..d96041b --- /dev/null +++ b/Towers/Modded/Omitions.md @@ -0,0 +1,30 @@ +# Omitions +// Note only tower that would cause issues as a RogueTower are included here. + +TF2 Aimbot Tower: No Bottom Path + +Luigi: Only one path, also can crash the game with XX3 Mermonkeys + +Tralalero Tralala: Only one path. + +SentriesAsTowers (All Towers): Only one path each. + +BrothersMonkey (aka Rodrick and Zepyhr): Only one path each, included bosses may cause issues. + +Boss Rush Recharged (Banana Farmer and Tech Bot): No upgrades, included bosses may cause issues. + +ChirstmasMod (ElvenWorkshop and Elfs): Only one path and no upgrades respectivly, included bosses may cause issues. + +Special Agents (All Towers): Only 1 upgrade. + +Powers in Shop (All Towers): No upgrades. + +// I think these could work as `HeroSelect` exclusive "heros". + +Augmenter: No standard upgrades. + +Ancient Monkey: No standard upgrades. + +Enhancement Monkey: No standard upgrades. + +Time Soldier: No standard upgrades. \ No newline at end of file diff --git a/Towers/Modded/PlasmaMonkey.cs b/Towers/Modded/PlasmaMonkey.cs new file mode 100644 index 0000000..11b273d --- /dev/null +++ b/Towers/Modded/PlasmaMonkey.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class PlasmaMonkey : RogueTower +{ + public override string BaseTowerId => "DarksTowers-PlasmaMonkey"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/Powers/BananaFarmerPro.cs b/Towers/Modded/Powers/BananaFarmerPro.cs new file mode 100644 index 0000000..002b5e7 --- /dev/null +++ b/Towers/Modded/Powers/BananaFarmerPro.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class BananaFarmerPro : RoguePowerProTower { + public override string BaseTowerId => "PowersInShop-BananaFarmerPro"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 1), new(1, 1), new(1, 1)]; +} \ No newline at end of file diff --git a/Towers/Modded/Powers/RoguePower.cs b/Towers/Modded/Powers/RoguePower.cs new file mode 100644 index 0000000..7199b5a --- /dev/null +++ b/Towers/Modded/Powers/RoguePower.cs @@ -0,0 +1,28 @@ +using BTD_Mod_Helper.Api; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models.Towers; +using Il2CppAssets.Scripts.Unity; +using Il2CppAssets.Scripts.Unity.UI_New.InGame; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace BTD6Rogue +{ + public abstract class RoguePowerTower : RogueTower + { + public override bool ChoiceBlacklisted => StaticChoiceBlacklisted; + public static bool StaticChoiceBlacklisted => ModifierUtil.HasModifier() || RogueModSettings.AllowPowersInShop == RogueModSettings.AllowPowersEnum.Unlimited /*|| !ModifierUtil.HasModifier()*/; + public override bool SelectBlacklisted => StaticSelectBlacklisted; + public static bool StaticSelectBlacklisted => ModifierUtil.HasModifier() || RogueModSettings.AllowPowersInShop == RogueModSettings.AllowPowersEnum.None; + + // Get the RogueTower's TowerModel at a path and tier of that path + // TODO: make it so it can get crosspaths, additionally combine functionality with getbasetower + public override TowerModel GetTower(int[] tiers) + { + return Game.instance.model.GetTowerModel(BaseTowerId, 0, 0, 0); + } + public override void Register() { } + } +} diff --git a/Towers/Modded/Powers/RoguePowerProTower.cs b/Towers/Modded/Powers/RoguePowerProTower.cs new file mode 100644 index 0000000..26fe24c --- /dev/null +++ b/Towers/Modded/Powers/RoguePowerProTower.cs @@ -0,0 +1,26 @@ +using BTD_Mod_Helper.Api; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models.Towers; +using Il2CppAssets.Scripts.Unity; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace BTD6Rogue +{ + public abstract class RoguePowerProTower : RogueTower + { + public override bool ChoiceBlacklisted => ModifierUtil.HasModifier() && !RogueModSettings.AllowProPowersAsMonkeys; + public override bool SelectBlacklisted => ModifierUtil.HasModifier() && !RogueModSettings.AllowProPowersAsMonkeys; + public static bool StaticBlacklisted => ModifierUtil.HasModifier() && !RogueModSettings.AllowProPowersAsMonkeys; + + // Get the RogueTower's TowerModel at a path and tier of that path + // TODO: make it so it can get crosspaths, additionally combine functionality with getbasetower + public override TowerModel GetTower(int[] tiers) + { + return Game.instance.model.GetTowerModel(BaseTowerId, Math.Max(tiers[0] - 2, 0), Math.Max(tiers[1] - 2, 0), Math.Max(tiers[2] - 2, 0)); + } + public override void Register() { } + } +} diff --git a/Towers/Modded/Powers/SuperMonkeyBeacon.cs b/Towers/Modded/Powers/SuperMonkeyBeacon.cs new file mode 100644 index 0000000..2015c71 --- /dev/null +++ b/Towers/Modded/Powers/SuperMonkeyBeacon.cs @@ -0,0 +1,10 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class SuperMonkeyBeacon : RoguePowerProTower { + public override string BaseTowerId => "PowersInShop-SuperMonkeyBeacon"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 1), new(1, 1), new(1, 1)]; +} \ No newline at end of file diff --git a/Towers/Modded/Psychomonkey.cs b/Towers/Modded/Psychomonkey.cs new file mode 100644 index 0000000..b2a3f5d --- /dev/null +++ b/Towers/Modded/Psychomonkey.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class Psychomonkey : RogueTower +{ + public override string BaseTowerId => "psychomonkey-Psychomonkey"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/SaudaTower.cs b/Towers/Modded/SaudaTower.cs new file mode 100644 index 0000000..b4ff8d7 --- /dev/null +++ b/Towers/Modded/SaudaTower.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class SaudaTower : RogueTower +{ + public override string BaseTowerId => "SaudaMod-SaudaTower"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/SecretTack.cs b/Towers/Modded/SecretTack.cs new file mode 100644 index 0000000..a9da9fc --- /dev/null +++ b/Towers/Modded/SecretTack.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class SecretTack : RogueTower +{ + public override string BaseTowerId => "SecretTack-SecretTack"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Modded/TempleBase.cs b/Towers/Modded/TempleBase.cs new file mode 100644 index 0000000..d463af4 --- /dev/null +++ b/Towers/Modded/TempleBase.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class TempleBase : RogueTower +{ + public override string BaseTowerId => "TempleBaseMod-TempleBase"; + public override Dictionary TowerTags => []; + public override Vector2Int[] TowerAmountRanges => [new(1, 3), new(1, 3), new(1, 3)]; +} \ No newline at end of file diff --git a/Towers/Paragons/ModdedParagons/CaveMonkeyParagon.cs b/Towers/Paragons/ModdedParagons/CaveMonkeyParagon.cs new file mode 100644 index 0000000..49900c8 --- /dev/null +++ b/Towers/Paragons/ModdedParagons/CaveMonkeyParagon.cs @@ -0,0 +1,10 @@ +using BTD_Mod_Helper.Api.Towers; +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +//Idk if it actually has a Paragon? +public class CaveMonkeyParagon : RogueParagon { + public override string DisplayName => "Cave Monkey Paragon"; + public override string BaseTowerId => "CaveMonkeyV2-CaveMonkey"; +} diff --git a/Towers/Paragons/ModdedParagons/CyberMonkey.cs b/Towers/Paragons/ModdedParagons/CyberMonkey.cs new file mode 100644 index 0000000..63b9a03 --- /dev/null +++ b/Towers/Paragons/ModdedParagons/CyberMonkey.cs @@ -0,0 +1,11 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class MegaMechaMonke : RogueParagon +{ + public override string BaseTowerId => "DarksTowers-CyberMonkey"; + public override string DisplayName => "Mega Mecha Monke"; +} \ No newline at end of file diff --git a/Towers/Paragons/ModdedParagons/GodKingOfSpades.cs b/Towers/Paragons/ModdedParagons/GodKingOfSpades.cs new file mode 100644 index 0000000..b1bf65b --- /dev/null +++ b/Towers/Paragons/ModdedParagons/GodKingOfSpades.cs @@ -0,0 +1,8 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class GodKingOfSpades : RogueParagon { + public override string DisplayName => "God King Of Spades"; + public override string BaseTowerId => "CardMonkey-CardMonkey"; +} diff --git a/Towers/Paragons/ModdedParagons/MasterBakery.cs b/Towers/Paragons/ModdedParagons/MasterBakery.cs new file mode 100644 index 0000000..2520d27 --- /dev/null +++ b/Towers/Paragons/ModdedParagons/MasterBakery.cs @@ -0,0 +1,12 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class MasterBakeryV1 : RogueParagon { + public override string DisplayName => "Master Bakery"; + public override string BaseTowerId => "BakerMonkeyMod-BakerMonkey"; +} +public class MasterBakeryV2 : RogueParagon { + public override string DisplayName => "Master Bakery"; + public override string BaseTowerId => "BakerMonkeyModV2-BakerMonkey"; +} diff --git a/Towers/Paragons/ModdedParagons/MonkeyOfLight.cs b/Towers/Paragons/ModdedParagons/MonkeyOfLight.cs new file mode 100644 index 0000000..eedd04d --- /dev/null +++ b/Towers/Paragons/ModdedParagons/MonkeyOfLight.cs @@ -0,0 +1,11 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class DiscordLightMode : RogueParagon +{ + public override string BaseTowerId => "DarksTowers-MonkeyofLight"; + public override string DisplayName => "Discord Light Mode"; +} \ No newline at end of file diff --git a/Towers/Paragons/ModdedParagons/PlasmaMonkey.cs b/Towers/Paragons/ModdedParagons/PlasmaMonkey.cs new file mode 100644 index 0000000..4c38a42 --- /dev/null +++ b/Towers/Paragons/ModdedParagons/PlasmaMonkey.cs @@ -0,0 +1,11 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class PlasmaLord : RogueParagon +{ + public override string BaseTowerId => "DarksTowers-PlasmaMonkey"; + public override string DisplayName => "Plasma Lord"; +} \ No newline at end of file diff --git a/Towers/Paragons/ModdedParagons/PotassiumSupreme.cs b/Towers/Paragons/ModdedParagons/PotassiumSupreme.cs new file mode 100644 index 0000000..ce6d9da --- /dev/null +++ b/Towers/Paragons/ModdedParagons/PotassiumSupreme.cs @@ -0,0 +1,8 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class PotassiumSupreme : RogueParagon { + public override string DisplayName => "Potassium Supreme"; + public override string BaseTowerId => "BananaFarmerMod-BananaFarmerTower"; +} diff --git a/Tower/Paragons/ParagonData.cs b/Towers/Paragons/ParagonData.cs similarity index 100% rename from Tower/Paragons/ParagonData.cs rename to Towers/Paragons/ParagonData.cs diff --git a/Tower/Paragons/ParagonUtil.cs b/Towers/Paragons/ParagonUtil.cs similarity index 87% rename from Tower/Paragons/ParagonUtil.cs rename to Towers/Paragons/ParagonUtil.cs index 50493c2..75d7242 100644 --- a/Tower/Paragons/ParagonUtil.cs +++ b/Towers/Paragons/ParagonUtil.cs @@ -14,12 +14,12 @@ public static List GetEnabledRogueParagons(RogueGame game) { if (tower.GetBaseTower() is null || tower.GetBaseParagon() is null) { - BTD6Rogue.LogMessage("The RogueParagon " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a null tower.", tower, ErrorLevels.Error); + BTD6Rogue.LogMessage("The RogueParagon " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a null tower.", tower, ErrorLevels.Debug); continue; } - if (tower.GetBaseTower().towerSet == Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Hero) + if (tower.GetBaseTower().towerSet != Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Paragon) { - BTD6Rogue.LogMessage("The RogueParagon " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a tower in the Hero TowerSet. This may cause issues.", tower, ErrorLevels.Warning); + BTD6Rogue.LogMessage("The RogueParagon " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a 'Paragon' outside the Paragon TowerSet. This may cause issues.", tower, ErrorLevels.Debug); } if (game.towerManager.disabledTowerSets.Contains(Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Paragon)) { continue; @@ -68,7 +68,7 @@ public static ParagonChoice[] CreateValidParagonChoices(RogueGame rogueGame) { List paragons = new List(); List possibleChoices = CreateAllValidParagonChoices(rogueGame); - if (possibleChoices.Count < 3) { return null!; } + if (possibleChoices.Count < 3 || (possibleChoices.Count < 2 && ModifierUtil.HasModifier())) { return null!; } while (paragons.Count < 3) { ParagonChoice towerChoice = possibleChoices[new Random().Next(possibleChoices.Count)]; diff --git a/Tower/Paragons/RogueParagon.cs b/Towers/Paragons/RogueParagon.cs similarity index 100% rename from Tower/Paragons/RogueParagon.cs rename to Towers/Paragons/RogueParagon.cs diff --git a/Tower/Paragons/VanillaParagons/ApexPlasmaMaster.cs b/Towers/Paragons/VanillaParagons/ApexPlasmaMaster.cs similarity index 100% rename from Tower/Paragons/VanillaParagons/ApexPlasmaMaster.cs rename to Towers/Paragons/VanillaParagons/ApexPlasmaMaster.cs diff --git a/Tower/Paragons/VanillaParagons/AscendedShadow.cs b/Towers/Paragons/VanillaParagons/AscendedShadow.cs similarity index 100% rename from Tower/Paragons/VanillaParagons/AscendedShadow.cs rename to Towers/Paragons/VanillaParagons/AscendedShadow.cs diff --git a/Towers/Paragons/VanillaParagons/BallisticObliterationMissileBunker.cs b/Towers/Paragons/VanillaParagons/BallisticObliterationMissileBunker.cs new file mode 100644 index 0000000..ed32c84 --- /dev/null +++ b/Towers/Paragons/VanillaParagons/BallisticObliterationMissileBunker.cs @@ -0,0 +1,8 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class BallisticObliterationMissileBunker : RogueParagon { + public override string DisplayName => "Ballistic Obliteration Missile Bunker"; + public override string BaseTowerId => "BombShooter"; +} diff --git a/Tower/Paragons/VanillaParagons/CrucibleOfSteelAndFlame.cs b/Towers/Paragons/VanillaParagons/CrucibleOfSteelAndFlame.cs similarity index 100% rename from Tower/Paragons/VanillaParagons/CrucibleOfSteelAndFlame.cs rename to Towers/Paragons/VanillaParagons/CrucibleOfSteelAndFlame.cs diff --git a/Tower/Paragons/VanillaParagons/GlaiveDominus.cs b/Towers/Paragons/VanillaParagons/GlaiveDominus.cs similarity index 100% rename from Tower/Paragons/VanillaParagons/GlaiveDominus.cs rename to Towers/Paragons/VanillaParagons/GlaiveDominus.cs diff --git a/Tower/Paragons/VanillaParagons/GoliathDoomship.cs b/Towers/Paragons/VanillaParagons/GoliathDoomship.cs similarity index 100% rename from Tower/Paragons/VanillaParagons/GoliathDoomship.cs rename to Towers/Paragons/VanillaParagons/GoliathDoomship.cs diff --git a/Towers/Paragons/VanillaParagons/HeraldOfEverfrost.cs b/Towers/Paragons/VanillaParagons/HeraldOfEverfrost.cs new file mode 100644 index 0000000..b8478ae --- /dev/null +++ b/Towers/Paragons/VanillaParagons/HeraldOfEverfrost.cs @@ -0,0 +1,13 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BTD6Rogue; + +public class HeraldOfEverfrost : RogueParagon { + public override string DisplayName => "Herald of Everfrost"; + public override string BaseTowerId => TowerType.IceMonkey; +} diff --git a/Tower/Paragons/VanillaParagons/MagusPerfectus.cs b/Towers/Paragons/VanillaParagons/MagusPerfectus.cs similarity index 100% rename from Tower/Paragons/VanillaParagons/MagusPerfectus.cs rename to Towers/Paragons/VanillaParagons/MagusPerfectus.cs diff --git a/Tower/Paragons/VanillaParagons/MasterBuilder.cs b/Towers/Paragons/VanillaParagons/MasterBuilder.cs similarity index 100% rename from Tower/Paragons/VanillaParagons/MasterBuilder.cs rename to Towers/Paragons/VanillaParagons/MasterBuilder.cs diff --git a/Towers/Paragons/VanillaParagons/MegaMassiveMunitionsFactory.cs b/Towers/Paragons/VanillaParagons/MegaMassiveMunitionsFactory.cs new file mode 100644 index 0000000..580303b --- /dev/null +++ b/Towers/Paragons/VanillaParagons/MegaMassiveMunitionsFactory.cs @@ -0,0 +1,8 @@ +using Il2CppAssets.Scripts.Models.Towers; + +namespace BTD6Rogue; + +public class MegaMassiveMunitionsFactory : RogueParagon { + public override string DisplayName => "Mega Massive Munitions Factory"; + public override string BaseTowerId => TowerType.SpikeFactory; +} diff --git a/Tower/Paragons/VanillaParagons/NauticSiegeCore.cs b/Towers/Paragons/VanillaParagons/NauticSiegeCore.cs similarity index 100% rename from Tower/Paragons/VanillaParagons/NauticSiegeCore.cs rename to Towers/Paragons/VanillaParagons/NauticSiegeCore.cs diff --git a/Tower/Paragons/VanillaParagons/NavarchOfTheSeas.cs b/Towers/Paragons/VanillaParagons/NavarchOfTheSeas.cs similarity index 100% rename from Tower/Paragons/VanillaParagons/NavarchOfTheSeas.cs rename to Towers/Paragons/VanillaParagons/NavarchOfTheSeas.cs diff --git a/Towers/PrismUtil.cs b/Towers/PrismUtil.cs new file mode 100644 index 0000000..a029abc --- /dev/null +++ b/Towers/PrismUtil.cs @@ -0,0 +1,23 @@ +using BTD_Mod_Helper.Api; +using BTD_Mod_Helper.Api.Towers; +using BTD_Mod_Helper.Extensions; +using Il2CppAssets.Scripts.Models.Towers; +using Il2CppAssets.Scripts.Unity; +using Il2CppAssets.Scripts.Unity.UI_New.InGame; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BTD6Rogue; + +// Functions to handle common tower related code +// Code here should not change anything game data +// Handle all of that in TowerManager +public static class PrismUtil { + public static List CreateAllValidPrismChoices(RogueGame rogueGame) { + List towerChoices = [.. TowerUtil.CreateAllValidTowerChoices(rogueGame).Cast()]; + List heroChoices = [.. HeroUtil.CreateAllValidHeroChoices(rogueGame).Cast()]; + towerChoices.AddRange(heroChoices); + return towerChoices; + } +} diff --git a/Tower/RogueTower.cs b/Towers/RogueTower.cs similarity index 65% rename from Tower/RogueTower.cs rename to Towers/RogueTower.cs index 04ca43e..41812ad 100644 --- a/Tower/RogueTower.cs +++ b/Towers/RogueTower.cs @@ -29,8 +29,15 @@ public abstract class RogueTower : NamedModContent { // Optional as it should be able to automatically generate (both so I have less work and also to provide functionality for modded towers) public abstract Vector2Int[] TowerAmountRanges { get; } - // Get the RogueTower's TowerModel at 0-0-0 - public virtual TowerModel GetBaseTower() { + // Blacklists the RogueTower for Tower Choices/Selection + public virtual bool ChoiceBlacklisted => false; + public virtual bool SelectBlacklisted => false; + + // Removes a + public virtual bool ConsumeWhenPlace => false; + + // Get the RogueTower's TowerModel at 0-0-0 + public virtual TowerModel GetBaseTower() { return Game.instance.model.GetTowerModel(BaseTowerId); } @@ -43,12 +50,30 @@ public virtual TowerModel GetTower(int[] tiers) { // Generate a random number based off the tower amount range set for a RogueTower public virtual int GetTowerAmount(int[] tiers) { int path = Array.IndexOf(tiers, tiers.Max()); - if (TowerAmountRanges[path].x == 0 && TowerAmountRanges[path].y == 0) { - return new System.Random().Next(1, 4); - } else { - return new System.Random().Next(TowerAmountRanges[path].x, TowerAmountRanges[path].y + 1); + if (ModifierUtil.HasModifier()){ + if (TowerAmountRanges[path].x == 0 && TowerAmountRanges[path].y == 0) + { + return new System.Random().Next(0, 3); + } + else + { + return new System.Random().Next(Math.Max(TowerAmountRanges[path].x - 1, 0), TowerAmountRanges[path].y); + } + } + else + { + if (TowerAmountRanges[path].x == 0 && TowerAmountRanges[path].y == 0) + { + return new System.Random().Next(1, 4); + } + else + { + return new System.Random().Next(TowerAmountRanges[path].x, TowerAmountRanges[path].y + 1); + } } } + public virtual int GetTowerAmountForChoice() { return 1; } + public override void Register() {} } diff --git a/Tower/TowerData.cs b/Towers/TowerData.cs similarity index 91% rename from Tower/TowerData.cs rename to Towers/TowerData.cs index 308b78a..0556de5 100644 --- a/Tower/TowerData.cs +++ b/Towers/TowerData.cs @@ -41,16 +41,21 @@ public enum TowerTag { Military, // Military tower or buffs Military towers Magic, // Magic tower or buffs Magic towers Support, // Support tower or buffs Support towers + Powers, // Powers/Special Agents or buffs Powers/Special Agents + Heroes, // buffs Heroes Water, // Placed in water Land, // Placed on land Normal, // Deals normal damage Acid, // Deals acid damage Fire, // Deals fire damage Plasma, // Deals plasma damage + Incendiary, // Deals "incendiary" damage (Weak to Purple and Black) Explosion, // Deals explosion damage Shatter, // Deals shatter damage Glacier, // Deals glacier damage + Frigid, // Deals frigid damage Energy, // Deals energy damage + Frost, // Deals "frost" damage (Weak to Lead, Purple and White) Sharp, // Deals sharp damage Cold, // Deals cold damage Passive, // Doesn't deal damage diff --git a/Tower/TowerManager.cs b/Towers/TowerManager.cs similarity index 87% rename from Tower/TowerManager.cs rename to Towers/TowerManager.cs index 0957e01..91f1967 100644 --- a/Tower/TowerManager.cs +++ b/Towers/TowerManager.cs @@ -27,19 +27,21 @@ public void ClearTowerInventory() { TowerInventory towerInventory = game.GetTowerInventory(); Dictionary towerMaxes = towerInventory.GetTowerInventoryMaxes(); - foreach (string tower in TowerType.towers) { + foreach (string tower in TowerType.towers) + { + if ((tower.Contains("PowersInShop") && RogueModSettings.AllowPowersInShop != RogueModSettings.AllowPowersEnum.Unlimited && !ModifierUtil.HasModifier()) && !tower.Contains("Pro")) continue; + if ((tower == "PowersInShop-BananaFarmer" || tower == "PowersInShop-TechBot") && (RogueModSettings.AllowPowersInShop == RogueModSettings.AllowPowersEnum.Standard) && !ModifierUtil.HasModifier()) continue; if (towerMaxes.ContainsKey(tower)) { towerMaxes[tower] = 0; } else { towerMaxes.Add(tower, 0); } - } - + } towerInventory.towerMaxes = towerMaxes; UpdateInventory(); } - public void DisableTowerSet(TowerSet towerSet, bool towerSetDisabled = true) { + public void DisableTowerSet(TowerSet towerSet, bool towerSetDisabled = true) { if (towerSetDisabled && !disabledTowerSets.Contains(towerSet)) { disabledTowerSets.Add(towerSet); } else if (!towerSetDisabled && disabledTowerSets.Contains(towerSet)) { @@ -47,7 +49,7 @@ public void DisableTowerSet(TowerSet towerSet, bool towerSetDisabled = true) { } } - public void DisableWaterTowers(bool waterTowersDisabled = true) { + public void DisableWaterTowers(bool waterTowersDisabled = true) { disableWaterTowers = waterTowersDisabled; } diff --git a/Tower/TowerUtil.cs b/Towers/TowerUtil.cs similarity index 75% rename from Tower/TowerUtil.cs rename to Towers/TowerUtil.cs index f5c7a2e..feab104 100644 --- a/Tower/TowerUtil.cs +++ b/Towers/TowerUtil.cs @@ -2,6 +2,7 @@ using BTD_Mod_Helper.Api.Towers; using BTD_Mod_Helper.Extensions; using Il2CppAssets.Scripts.Models.Towers; +using Il2CppAssets.Scripts.Unity; using Il2CppAssets.Scripts.Unity.UI_New.InGame; using System; using System.Collections.Generic; @@ -20,71 +21,98 @@ public static List GetEnabledRogueTowers(RogueGame game) { foreach (RogueTower tower in ModContent.GetContent()) { if (tower.GetBaseTower() is null) { - BTD6Rogue.LogMessage("The RogueTower " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a null tower. It has been disabled.", tower, ErrorLevels.Error); + BTD6Rogue.LogMessage("The RogueTower " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a null tower. It has been disabled.", tower, ErrorLevels.Debug); + continue; + } + if (tower.GetBaseTower().cost < 0) + { + BTD6Rogue.LogMessage("The RogueTower " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a tower with a negative cost. It has been disabled.", tower, ErrorLevels.Debug); continue; } - if (tower.GetBaseTower().towerSet == Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Hero) { - BTD6Rogue.LogMessage("The RogueTower " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a tower in the Hero TowerSet. This may cause issues.", tower, ErrorLevels.Warning); + BTD6Rogue.LogMessage("The RogueTower " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a tower in the Hero TowerSet. This may cause issues.", tower, ErrorLevels.Debug); } - if (tower.GetBaseTower().towerSet == Il2CppAssets.Scripts.Models.TowerSets.TowerSet.Paragon) { - BTD6Rogue.LogMessage("The RogueTower " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a (base) tower in the Paragon TowerSet. This may cause issues.", tower, ErrorLevels.Warning); + BTD6Rogue.LogMessage("The RogueTower " + tower.Name + "'s BaseTowerId (" + tower.BaseTowerId + ") returns a (base) tower in the Paragon TowerSet. This may cause issues.", tower, ErrorLevels.Debug); } - if (game.towerManager.disabledTowerSets.Contains(tower.GetBaseTower().towerSet)) { continue; } - if (game.towerManager.disableWaterTowers && tower.GetBaseTower().IsExclusivelyWaterBased) { continue; } enabledTowers.Add(tower); } - return enabledTowers; } - public static TowerChoice[] GetTier0TowersChoiceData(RogueGame game) { + public static TowerChoice[] GetTier0TowersChoiceData(RogueGame game) + { List towerChoices = new List(); List rogueTowers = GetEnabledRogueTowers(game); - foreach (RogueTower rogueTower in rogueTowers) { + foreach (RogueTower rogueTower in rogueTowers) + { + if (rogueTower.ChoiceBlacklisted) { continue; } towerChoices.Add(CreateTowerChoiceData(rogueTower, [0, 0, 0])); } return towerChoices.ToArray(); } - public static TowerChoice CreateTowerChoiceData(RogueTower tower, int[] tiers) { - TowerModel towerModel = tower.GetTower(tiers); + public static TowerChoice? CreateTowerChoiceData(RogueTower tower, int[] tiers) { + TowerModel towerModel = tower.GetTower(tiers); int path = Array.IndexOf(tiers, tiers.Max()); - string towerName = tower.GetTower(tiers).GetBaseId(); + //if (tower is RoguePowerProTower) { tiers = [tiers[0] - 2, tiers[1] - 2, tiers[2] - 2]; } + + string towerName = tower.GetTower(tiers).GetBaseId(); if (tiers[path] > 0) { - towerName = towerModel.GetUpgrade(path, tiers[path]).name; + try { + towerName = towerModel.GetUpgrade(path, tiers[path]).name; + } + catch { + BTD6Rogue.LogMessage("The tier " + tiers[path] + " UPGRADE for the " + (1 + path) + "th path for the '" + towerName + "' tower is null.", "TowerUtil.CreateTowerChoiceData", ErrorLevels.Error); + towerName += "(Path " + (1 + path) + ")"; + } } return new TowerChoice(tower.BaseTowerId, towerName, tower.GetTowerAmount(tiers), tiers, tower, tower.GetTower(tiers).portrait, tower.GetTower(tiers)); } - public static TowerChoice[] CreateTowerChoiceDatas(RogueTower tower, int tier) { - List towerChoices = new List(); + public static TowerChoice[] CreateTowerChoiceDatas(RogueTower tower, int tier) { + List towerChoices = new List(); + + if (tower is RoguePowerProTower) { tier -= 2; if (tier > 3) { tier = 3; } } + + TowerModel path2Tower = tower.GetTower([0, tier, 0]); + + if (path2Tower.GetUpgrade(1, tier) is null) { + towerChoices.Add(CreateTowerChoiceData(tower, [0, 0, 0])); + return towerChoices.ToArray(); + } TowerModel path1Tower = tower.GetTower([tier, 0, 0]); - TowerModel path2Tower = tower.GetTower([0, tier, 0]); TowerModel path3Tower = tower.GetTower([0, 0, tier]); string path1Name = path1Tower.GetBaseId(); string path2Name = path2Tower.GetBaseId(); string path3Name = path3Tower.GetBaseId(); - if (tier > 0) { + + if (tier > 0) + { path1Name = path1Tower.GetUpgrade(0, tier).name; path2Name = path2Tower.GetUpgrade(1, tier).name; path3Name = path3Tower.GetUpgrade(2, tier).name; } + else if (tower is RoguePowerProTower) + { + path1Name += " (Path 1)"; + path2Name += " (Path 2)"; + path3Name += " (Path 3)"; + } towerChoices.Add(new TowerChoice(tower.BaseTowerId, path1Name, tower.GetTowerAmount([tier, 0, 0]), [tier, 0, 0], tower, path1Tower.portrait, path1Tower)); towerChoices.Add(new TowerChoice(tower.BaseTowerId, path2Name, tower.GetTowerAmount([0, tier, 0]), [0, tier, 0], tower, path2Tower.portrait, path2Tower)); @@ -119,7 +147,8 @@ public static TowerData MergeTowerData(TowerData tower1, TowerData tower2) { public static TowerData CreateDataFromChoice(TowerChoice choiceData) { int[] towerPaths = [Math.Max(choiceData.towerPaths[0], 2), Math.Max(choiceData.towerPaths[1], 2), Math.Max(choiceData.towerPaths[2], 2)]; - TowerData towerData = new TowerData(choiceData.towerId, towerPaths, count: choiceData.towerAmount); + if (choiceData.rogueTower is RoguePowerProTower) towerPaths = [Math.Max(choiceData.towerPaths[0], 0), Math.Max(choiceData.towerPaths[1], 0), Math.Max(choiceData.towerPaths[2], 0)]; + TowerData towerData = new TowerData(choiceData.towerId, towerPaths, count: choiceData.towerAmount); return towerData; } @@ -133,9 +162,9 @@ public static List CreateAllValidTowerChoices(RogueGame rogueGame) foreach (RogueTower rogueTower in rogueTowers) { if (playerTowers.ContainsKey(rogueTower.BaseTowerId)) { if (playerTowers[rogueTower.BaseTowerId].locked) { continue; } - if (!playerTowers[rogueTower.BaseTowerId].limitPaths[0]) { towerChoices.Add(CreateTowerChoiceData(rogueTower, [tier, 0, 0])); } - if (!playerTowers[rogueTower.BaseTowerId].limitPaths[1]) { towerChoices.Add(CreateTowerChoiceData(rogueTower, [0, tier, 0])); } - if (!playerTowers[rogueTower.BaseTowerId].limitPaths[2]) { towerChoices.Add(CreateTowerChoiceData(rogueTower, [0, 0, tier])); } + if (!playerTowers[rogueTower.BaseTowerId].limitPaths[0] && CreateTowerChoiceData(rogueTower, [tier, 0, 0]) is not null) { towerChoices.Add(CreateTowerChoiceData(rogueTower, [tier, 0, 0])); } + if (!playerTowers[rogueTower.BaseTowerId].limitPaths[1] && CreateTowerChoiceData(rogueTower, [0, tier, 0]) is not null) { towerChoices.Add(CreateTowerChoiceData(rogueTower, [0, tier, 0])); } + if (!playerTowers[rogueTower.BaseTowerId].limitPaths[2] && CreateTowerChoiceData(rogueTower, [0, 0, tier]) is not null) { towerChoices.Add(CreateTowerChoiceData(rogueTower, [0, 0, tier])); } } else { towerChoices.AddRange(CreateTowerChoiceDatas(rogueTower, tier)); } @@ -144,27 +173,28 @@ public static List CreateAllValidTowerChoices(RogueGame rogueGame) return towerChoices; } - public static TowerChoice[] CreateValidTowerChoices(RogueGame rogueGame) { + public static TowerChoice[] CreateValidTowerChoices(RogueGame rogueGame) + { List towers = new List(); List possibleChoices = CreateAllValidTowerChoices(rogueGame); - if (possibleChoices.Count < 3) { return null!; } + if (possibleChoices.Count < 3 || (possibleChoices.Count < 2 && ModifierUtil.HasModifier())) { return null!; } - while (towers.Count < 3) { + while (towers.Count < 3 || (towers.Count < 2 && ModifierUtil.HasModifier())) + { TowerChoice towerChoice = possibleChoices[new Random().Next(possibleChoices.Count)]; - if (towers.Contains(towerChoice)) { continue; } + if (towers.Contains(towerChoice) || towerChoice.rogueTower.ChoiceBlacklisted) { continue; } towers.Add(towerChoice); } - return towers.ToArray(); } - public static RogueTower GetRandomTower() { + public static RogueTower GetRandomTower() { List towers = ModContent.GetContent(); return towers[new Random().Next(towers.Count)]; } - /* + /* public static string[] GetAllTowerSets() { List towerSets = new List() { "Primary", "Military", "Magic", "Support" }; diff --git a/Tower/Vanilla/Alchemist.cs b/Towers/Vanilla/Alchemist.cs similarity index 100% rename from Tower/Vanilla/Alchemist.cs rename to Towers/Vanilla/Alchemist.cs diff --git a/Tower/Vanilla/BananaFarm.cs b/Towers/Vanilla/BananaFarm.cs similarity index 100% rename from Tower/Vanilla/BananaFarm.cs rename to Towers/Vanilla/BananaFarm.cs diff --git a/Tower/Vanilla/BeastHandler.cs b/Towers/Vanilla/BeastHandler.cs similarity index 100% rename from Tower/Vanilla/BeastHandler.cs rename to Towers/Vanilla/BeastHandler.cs diff --git a/Tower/Vanilla/BombShooter.cs b/Towers/Vanilla/BombShooter.cs similarity index 100% rename from Tower/Vanilla/BombShooter.cs rename to Towers/Vanilla/BombShooter.cs diff --git a/Tower/Vanilla/BoomerangMonkey.cs b/Towers/Vanilla/BoomerangMonkey.cs similarity index 100% rename from Tower/Vanilla/BoomerangMonkey.cs rename to Towers/Vanilla/BoomerangMonkey.cs diff --git a/Tower/Vanilla/DartMonkey.cs b/Towers/Vanilla/DartMonkey.cs similarity index 100% rename from Tower/Vanilla/DartMonkey.cs rename to Towers/Vanilla/DartMonkey.cs diff --git a/Tower/Vanilla/DartlingGunner.cs b/Towers/Vanilla/DartlingGunner.cs similarity index 100% rename from Tower/Vanilla/DartlingGunner.cs rename to Towers/Vanilla/DartlingGunner.cs diff --git a/Towers/Vanilla/Desperado.cs b/Towers/Vanilla/Desperado.cs new file mode 100644 index 0000000..e801918 --- /dev/null +++ b/Towers/Vanilla/Desperado.cs @@ -0,0 +1,13 @@ +using Il2CppAssets.Scripts.Models.Towers; +using System.Collections.Generic; +using UnityEngine; + +namespace BTD6Rogue; + +public class Desperado : RogueTower { + public override string BaseTowerId => TowerType.Desperado; + + public override Dictionary TowerTags => []; + + public override Vector2Int[] TowerAmountRanges => [new (2, 4), new(3, 5), new (1, 3)]; +} \ No newline at end of file diff --git a/Tower/Vanilla/Druid.cs b/Towers/Vanilla/Druid.cs similarity index 100% rename from Tower/Vanilla/Druid.cs rename to Towers/Vanilla/Druid.cs diff --git a/Tower/Vanilla/EngineerMonkey.cs b/Towers/Vanilla/EngineerMonkey.cs similarity index 100% rename from Tower/Vanilla/EngineerMonkey.cs rename to Towers/Vanilla/EngineerMonkey.cs diff --git a/Tower/Vanilla/GlueGunner.cs b/Towers/Vanilla/GlueGunner.cs similarity index 100% rename from Tower/Vanilla/GlueGunner.cs rename to Towers/Vanilla/GlueGunner.cs diff --git a/Tower/Vanilla/HeliPilot.cs b/Towers/Vanilla/HeliPilot.cs similarity index 100% rename from Tower/Vanilla/HeliPilot.cs rename to Towers/Vanilla/HeliPilot.cs diff --git a/Tower/Vanilla/IceMonkey.cs b/Towers/Vanilla/IceMonkey.cs similarity index 100% rename from Tower/Vanilla/IceMonkey.cs rename to Towers/Vanilla/IceMonkey.cs diff --git a/Tower/Vanilla/Mermonkey.cs b/Towers/Vanilla/Mermonkey.cs similarity index 100% rename from Tower/Vanilla/Mermonkey.cs rename to Towers/Vanilla/Mermonkey.cs diff --git a/Tower/Vanilla/MonkeyAce.cs b/Towers/Vanilla/MonkeyAce.cs similarity index 100% rename from Tower/Vanilla/MonkeyAce.cs rename to Towers/Vanilla/MonkeyAce.cs diff --git a/Tower/Vanilla/MonkeyBuccaneer.cs b/Towers/Vanilla/MonkeyBuccaneer.cs similarity index 100% rename from Tower/Vanilla/MonkeyBuccaneer.cs rename to Towers/Vanilla/MonkeyBuccaneer.cs diff --git a/Tower/Vanilla/MonkeySub.cs b/Towers/Vanilla/MonkeySub.cs similarity index 100% rename from Tower/Vanilla/MonkeySub.cs rename to Towers/Vanilla/MonkeySub.cs diff --git a/Tower/Vanilla/MonkeyVillage.cs b/Towers/Vanilla/MonkeyVillage.cs similarity index 100% rename from Tower/Vanilla/MonkeyVillage.cs rename to Towers/Vanilla/MonkeyVillage.cs diff --git a/Tower/Vanilla/MortarMonkey.cs b/Towers/Vanilla/MortarMonkey.cs similarity index 100% rename from Tower/Vanilla/MortarMonkey.cs rename to Towers/Vanilla/MortarMonkey.cs diff --git a/Tower/Vanilla/NinjaMonkey.cs b/Towers/Vanilla/NinjaMonkey.cs similarity index 100% rename from Tower/Vanilla/NinjaMonkey.cs rename to Towers/Vanilla/NinjaMonkey.cs diff --git a/Tower/Vanilla/SniperMonkey.cs b/Towers/Vanilla/SniperMonkey.cs similarity index 100% rename from Tower/Vanilla/SniperMonkey.cs rename to Towers/Vanilla/SniperMonkey.cs diff --git a/Tower/Vanilla/SpikeFactory.cs b/Towers/Vanilla/SpikeFactory.cs similarity index 100% rename from Tower/Vanilla/SpikeFactory.cs rename to Towers/Vanilla/SpikeFactory.cs diff --git a/Tower/Vanilla/SuperMonkey.cs b/Towers/Vanilla/SuperMonkey.cs similarity index 100% rename from Tower/Vanilla/SuperMonkey.cs rename to Towers/Vanilla/SuperMonkey.cs diff --git a/Tower/Vanilla/TackShooter.cs b/Towers/Vanilla/TackShooter.cs similarity index 100% rename from Tower/Vanilla/TackShooter.cs rename to Towers/Vanilla/TackShooter.cs diff --git a/Tower/Vanilla/WizardMonkey.cs b/Towers/Vanilla/WizardMonkey.cs similarity index 100% rename from Tower/Vanilla/WizardMonkey.cs rename to Towers/Vanilla/WizardMonkey.cs