From 9063259c4a584a42bf17880733491cf88b62fc98 Mon Sep 17 00:00:00 2001 From: doombubbles Date: Sat, 14 Oct 2023 12:15:58 -0700 Subject: [PATCH] Add Degree Indicator --- LATEST.md | 4 +- ModHelperData.cs | 4 +- SacrificeHelperMod.cs | 122 +++++++++++++++++++++++++++++++----------- Utils.cs | 22 +++++--- 4 files changed, 109 insertions(+), 43 deletions(-) diff --git a/LATEST.md b/LATEST.md index ce2f2d8..fca0d11 100644 --- a/LATEST.md +++ b/LATEST.md @@ -1 +1,3 @@ -- Fixed Paragon costs getting included for Temple Sacrifice UI \ No newline at end of file +- Updated degree calculations for v39 changes +- Added Degree Indicator to the paragon investment slider +- Added mod setting to control the default Slider Contribution Penalty of 5% \ No newline at end of file diff --git a/ModHelperData.cs b/ModHelperData.cs index 9aff01e..91b4a3d 100644 --- a/ModHelperData.cs +++ b/ModHelperData.cs @@ -2,8 +2,8 @@ public static class ModHelperData { - public const string WorksOnVersion = "38.1"; - public const string Version = "2.3.4"; + public const string WorksOnVersion = "39.0"; + public const string Version = "2.4.0"; public const string Name = "Sacrifice Helper"; public const string Description = diff --git a/SacrificeHelperMod.cs b/SacrificeHelperMod.cs index e269a4a..6111967 100644 --- a/SacrificeHelperMod.cs +++ b/SacrificeHelperMod.cs @@ -2,16 +2,19 @@ using Il2CppAssets.Scripts.Simulation.Towers.Behaviors; using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu; using BTD_Mod_Helper; -using BTD_Mod_Helper.Api; using BTD_Mod_Helper.Api.Components; using BTD_Mod_Helper.Api.Enums; using BTD_Mod_Helper.Api.ModOptions; using BTD_Mod_Helper.Extensions; using HarmonyLib; +using Il2Cpp; using Il2CppAssets.Scripts.Unity.UI_New.InGame; using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu.TowerSelectionMenuThemes; +using Il2CppAssets.Scripts.Unity.UI_New.Popups; +using Il2CppAssets.Scripts.Unity.UI_New.Utils; using MelonLoader; using SacrificeHelper; +using UnityEngine; [assembly: MelonInfo(typeof(SacrificeHelperMod), ModHelperData.Name, ModHelperData.Version, ModHelperData.RepoOwner)] [assembly: MelonGame("Ninja Kiwi", "BloonsTD6")] @@ -20,37 +23,51 @@ namespace SacrificeHelper; public class SacrificeHelperMod : BloonsTD6Mod { + public static readonly ModSettingDouble SliderContributionPenalty = new(0.05f) + { + description = "The popup added in BTD6 v39 comes with a default 5% penalty to manually invested cash.\n" + + "Setting this to 0 would stop it, or negative would counteract it.", + stepSize = .01f, + min = -.99, + max = 1, + icon = VanillaSprites.UpgradeContainerParagonUnlocked + }; + public static readonly ModSettingCategory ParagonPowerMaximums = new("Paragon Power Maximums"); - public static readonly ModSettingInt MaxFromPops = new(90000) + public static readonly ModSettingInt MaxPowerFromPops = new(90000) { displayName = "Max Paragon Power From Pops\n(-1 for unlimited)", min = -1, + max = 200000, icon = VanillaSprites.PopIcon, - category = ParagonPowerMaximums + category = ParagonPowerMaximums, }; - public static readonly ModSettingInt MaxFromCash = new(10000) + public static readonly ModSettingInt MaxPowerFromCash = new(60000) { displayName = "Max Paragon Power From Cash\n(-1 for unlimited)", min = -1, + max = 200000, icon = VanillaSprites.CoinIcon, category = ParagonPowerMaximums }; - public static readonly ModSettingInt MaxFromNonTier5s = new(10000) + public static readonly ModSettingInt MaxPowerFromNonTier5s = new(10000) { displayName = "Max Paragon Power From Non Tier 5s\n(-1 for unlimited)", min = -1, + max = 200000, icon = VanillaSprites.UpgradeContainerGrey, modifyOption = option => option.Icon.AddText(new Info("Text", InfoPreset.FillParent), "<5", 100), category = ParagonPowerMaximums }; - public static readonly ModSettingInt MaxFromTier5s = new(90000) + public static readonly ModSettingInt MaxPowerFromTier5s = new(50000) { displayName = "Max Paragon Power From Tier 5s\n(-1 for unlimited)", min = -1, + max = 200000, icon = VanillaSprites.UpgradeContainerTier5, modifyOption = option => option.Icon.AddText(new Info("Text", InfoPreset.FillParent), "5", 100), category = ParagonPowerMaximums @@ -58,7 +75,7 @@ public class SacrificeHelperMod : BloonsTD6Mod public static readonly ModSettingCategory ParagonPowerWeights = new("Paragon Power Weights"); - private static readonly ModSettingInt PopsPerPoint = new(180) + private static readonly ModSettingInt PopsScaleFactor = new(180) { displayName = "Pops per Point of Paragon Power", min = 1, @@ -66,15 +83,16 @@ public class SacrificeHelperMod : BloonsTD6Mod category = ParagonPowerWeights }; - private static readonly ModSettingInt CashPerPoint = new(25) + private static readonly ModSettingInt CashScaleFactor = new(20000) { - displayName = "Cash per Point of Paragon Power", + displayName = "Paragon Power Scale Factor for Cash", min = 1, icon = VanillaSprites.CoinIcon, - category = ParagonPowerWeights + category = ParagonPowerWeights, + description = "As of v39, the Paragon Upgrade Price is divided by this to get the final value" }; - private static readonly ModSettingInt NonTier5sScaleFactor = new(100) + private static readonly ModSettingInt NonTier5ScaleFactor = new(100) { displayName = "Paragon Power Scale Factor for Non Tier 5s", min = 0, @@ -83,7 +101,7 @@ public class SacrificeHelperMod : BloonsTD6Mod category = ParagonPowerWeights }; - private static readonly ModSettingInt Tier5sScaleFactor = new(10000) + private static readonly ModSettingInt Tier5ScaleFactor = new(6000) { displayName = "Paragon Power Scale Factor for Tier 5s", min = 0, @@ -120,35 +138,39 @@ public class SacrificeHelperMod : BloonsTD6Mod public override void OnNewGameModel(GameModel result) { - result.paragonDegreeDataModel.maxPowerFromPops = MaxFromPops; - if (result.paragonDegreeDataModel.maxPowerFromPops < 0) + var degreeData = result.paragonDegreeDataModel; + + degreeData.maxPowerFromPops = MaxPowerFromPops; + if (degreeData.maxPowerFromPops < 0) { - result.paragonDegreeDataModel.maxPowerFromPops = int.MaxValue; + degreeData.maxPowerFromPops = degreeData.MaxInvestment; } - result.paragonDegreeDataModel.maxPowerFromMoneySpent = MaxFromCash; - if (result.paragonDegreeDataModel.maxPowerFromMoneySpent < 0) + degreeData.maxPowerFromMoneySpent = MaxPowerFromCash; + if (degreeData.maxPowerFromMoneySpent < 0) { - result.paragonDegreeDataModel.maxPowerFromMoneySpent = int.MaxValue; + degreeData.maxPowerFromMoneySpent = degreeData.MaxInvestment; } - result.paragonDegreeDataModel.maxPowerFromNonTier5Count = MaxFromNonTier5s; - if (result.paragonDegreeDataModel.maxPowerFromNonTier5Count < 0) + degreeData.maxPowerFromNonTier5Count = MaxPowerFromNonTier5s; + if (degreeData.maxPowerFromNonTier5Count < 0) { - result.paragonDegreeDataModel.maxPowerFromNonTier5Count = int.MaxValue; + degreeData.maxPowerFromNonTier5Count = degreeData.MaxInvestment; } - result.paragonDegreeDataModel.maxPowerFromTier5Count = MaxFromTier5s; - if (result.paragonDegreeDataModel.maxPowerFromTier5Count < 0) + degreeData.maxPowerFromTier5Count = MaxPowerFromTier5s; + if (degreeData.maxPowerFromTier5Count < 0) { - result.paragonDegreeDataModel.maxPowerFromTier5Count = int.MaxValue; + degreeData.maxPowerFromTier5Count = degreeData.MaxInvestment; } - result.paragonDegreeDataModel.popsOverX = PopsPerPoint; - result.paragonDegreeDataModel.moneySpentOverX = CashPerPoint; - result.paragonDegreeDataModel.nonTier5TowersMultByX = NonTier5sScaleFactor; - result.paragonDegreeDataModel.tier5TowersMultByX = Tier5sScaleFactor; - + degreeData.popsOverX = PopsScaleFactor; + degreeData.moneySpentOverX = CashScaleFactor; + degreeData.nonTier5TowersMultByX = NonTier5ScaleFactor; + degreeData.tier5TowersMultByX = Tier5ScaleFactor; + + degreeData.paidContributionPenalty = SliderContributionPenalty; + templeSacrificesOff = false; } @@ -167,7 +189,7 @@ private static void Postfix(TowerSelectionMenu __instance) { var themeManager = __instance.themeManager; var currentTheme = themeManager.CurrentTheme; - + if (currentTheme == null) return; var ui = currentTheme.GetComponent(); @@ -177,8 +199,8 @@ private static void Postfix(TowerSelectionMenu __instance) } } } - - + + [HarmonyPatch(typeof(MenuThemeManager), nameof(MenuThemeManager.SetTheme))] internal static class MenuThemeManager_SetTheme { @@ -196,4 +218,40 @@ private static void Postfix(MenuThemeManager __instance, BaseTSMTheme newTheme) } } } + + [HarmonyPatch(typeof(ParagonConfirmationPopup), nameof(ParagonConfirmationPopup.UpdateCurrentInvestment))] + internal static class ParagonConfirmationPopup_UpdateCurrentInvestment + { + [HarmonyPostfix] + private static void Postfix(ParagonConfirmationPopup __instance, float current) + { + var tower = TowerSelectionMenu.instance.selectedTower; + + var degree = Utils.GetParagonDegree(tower, out _, current); + + var text = __instance.transform.GetComponentFromChildrenByName("DegreeText"); + text.SetText(degree.ToString()); + text.color = degree >= 100 ? Color.green : Color.white; + } + } + + [HarmonyPatch(typeof(ParagonConfirmationPopup), nameof(ParagonConfirmationPopup.Init), + typeof(Il2CppSystem.Action), typeof(Il2CppSystem.Action), typeof(int), typeof(int), typeof(int), + typeof(PopupScreen.BackGround), typeof(Popup.TransitionAnim))] + internal static class ParagonConfirmationPopup_Init + { + [HarmonyPostfix] + private static void Postfix(ParagonConfirmationPopup __instance) + { + var tower = TowerSelectionMenu.instance.selectedTower; + var degree = Utils.GetParagonDegree(tower, out _); + + var mainObject = __instance.animator.gameObject; + + var indicator = ModHelperImage.Create(new Info("DegreeIndicator", 0, -450, 250, 250), + VanillaSprites.UpgradeContainerParagon); + mainObject.AddModHelperComponent(indicator); + indicator.AddText(new Info("DegreeText", InfoPreset.FillParent), degree.ToString(), 100f); + } + } } \ No newline at end of file diff --git a/Utils.cs b/Utils.cs index 6c23fa2..631605a 100644 --- a/Utils.cs +++ b/Utils.cs @@ -115,7 +115,7 @@ private static float GetTowerSetWorth(string towerSet, Tower tower) => InGame.in activeAt = -1 }; - public static int GetParagonDegree(TowerToSimulation tower, out ParagonTower.InvestmentInfo investmentInfo) + public static int GetParagonDegree(TowerToSimulation tower, out ParagonTower.InvestmentInfo investmentInfo, float bonus = 0) { var degreeDataModel = InGame.instance.GetGameModel().paragonDegreeDataModel; var degree = 0; @@ -124,17 +124,23 @@ public static int GetParagonDegree(TowerToSimulation tower, out ParagonTower.Inv var paragonCost = tower.GetUpgradeCost(0, 6, -1, true); - // TODO seems like a bug with BTD6, should the paragon upgrade cost really be included ??? - tower.tower.worth += paragonCost; - var paragonTower = FakeParagonTower(tower.tower); + + paragonTower.upgradeCost = paragonCost; + + var bonusInvestment = new ParagonTower.InvestmentInfo + { + powerFromMoneySpent = (bonus * degreeDataModel.moneySpentOverX) / + ((1 + degreeDataModel.paidContributionPenalty) * paragonCost) + }; + investmentInfo = InGame.instance.GetAllTowerToSim() - .Where(tts => tts.Def.baseId == tower.Def.baseId || tts.Def.GetChild() != null) - .OrderBy(tts => paragonTower.GetTowerInvestment(tts.tower, 3).totalInvestment) + .Where(tts => + tts.Def.baseId == tower.Def.baseId || tts.Def.GetChild() != null) + .OrderBy(tts => paragonTower.GetTowerInvestment(tts.tower).totalInvestment) .Select(tts => paragonTower.GetTowerInvestment(tts.tower, tts.Def.tier >= 5 ? index++ : 3)) - .Aggregate(paragonTower.CombineInvestments); + .Aggregate(bonusInvestment, paragonTower.CombineInvestments); - tower.tower.worth -= paragonCost; var requirements = degreeDataModel.powerDegreeRequirements;