diff --git a/IRTweaks/IRTweaks/IRTweaks.csproj b/IRTweaks/IRTweaks/IRTweaks.csproj index b3ec41c..470ee88 100644 --- a/IRTweaks/IRTweaks/IRTweaks.csproj +++ b/IRTweaks/IRTweaks/IRTweaks.csproj @@ -115,6 +115,7 @@ + diff --git a/IRTweaks/IRTweaks/ModConfig.cs b/IRTweaks/IRTweaks/ModConfig.cs index 0e7f307..a8f4844 100644 --- a/IRTweaks/IRTweaks/ModConfig.cs +++ b/IRTweaks/IRTweaks/ModConfig.cs @@ -131,6 +131,7 @@ public class FixesFlags // UI public bool BulkPurchasing = true; + public bool BulkScrapping = true; public bool CombatLog = true; public bool DisableCombatRestarts = true; public bool DisableCombatSaves = true; @@ -166,6 +167,7 @@ public void LogConfig() Mod.Log.Info?.Write($" BuildingDamageColorChange: {this.Fixes.BuildingDamageColorChange}"); Mod.Log.Info?.Write($" BraceOnMeleeWithJuggernaut: {this.Fixes.BraceOnMeleeWithJuggernaut}"); Mod.Log.Info?.Write($" BulkPurchasing: {this.Fixes.BulkPurchasing}"); + Mod.Log.Info?.Write($" BulkScrapping: {this.Fixes.BulkScrapping}"); Mod.Log.Info?.Write($" CalledShotTweaks: {this.Fixes.CalledShotTweaks}"); Mod.Log.Info?.Write($" CombatLog: {this.Fixes.CombatLog}"); Mod.Log.Info?.Write($" DisableCampaign: {this.Fixes.DisableCampaign}"); diff --git a/IRTweaks/IRTweaks/ModText.cs b/IRTweaks/IRTweaks/ModText.cs index 1d9118f..f028604 100644 --- a/IRTweaks/IRTweaks/ModText.cs +++ b/IRTweaks/IRTweaks/ModText.cs @@ -4,6 +4,32 @@ namespace IRTweaks { public class ModText { + + public const string DT_Title_ScrapAll = "SCRAP_ALL_TITLE"; + public const string DT_Title_ScrapAssaults = "SCRAP_ALL_ASSAULT"; + public const string DT_Title_ScrapHeavies = "SCRAP_ALL_HEAVY"; + public const string DT_Title_ScrapLights = "SCRAP_ALL_LIGHT"; + public const string DT_Title_ScrapMediums = "SCRAP_ALL_MEDIUM"; + + public const string DT_Desc_ScrapAll = "SCRAP_ALL_DESC"; + public const string DT_Button_Cancel = "BUTTON_CANCEL"; + public const string DT_Button_Scrap = "BUTTON_SCRAP"; + + public Dictionary Dialog = new Dictionary + { + { DT_Title_ScrapAll, "SCRAP ALL IN STORAGE" }, + { DT_Title_ScrapAssaults, "SCRAP ASSAULTS IN STORAGE" }, + { DT_Title_ScrapHeavies, "SCRAP HEAVIES IN STORAGE" }, + { DT_Title_ScrapLights, "SCRAP LIGHTS IN STORAGE" }, + { DT_Title_ScrapMediums, "SCRAP MEDIUMS IN STORAGE" }, + + { DT_Desc_ScrapAll, "This will scrap units currently in storage, gaining {0} c-bills. This action cannot be reversed, you will need to load an earlier save. Are you sure?" }, + + { DT_Button_Cancel, "CANCEL" }, + { DT_Button_Scrap, "SCRAP" } + + }; + public const string FT_InjuryResist = "INJURY_RESIST"; public Dictionary Floaties = new Dictionary diff --git a/IRTweaks/IRTweaks/Modules/Combat/BuildingDamageColorChange.cs b/IRTweaks/IRTweaks/Modules/Combat/BuildingDamageColorChange.cs index 0cde805..3e0892e 100644 --- a/IRTweaks/IRTweaks/Modules/Combat/BuildingDamageColorChange.cs +++ b/IRTweaks/IRTweaks/Modules/Combat/BuildingDamageColorChange.cs @@ -6,13 +6,16 @@ namespace IRTweaks.Modules.Combat { // make buildings have blue damage number floaties to differentiate [HarmonyPatch(typeof(CombatHUDFloatie), "Init")] - public static class CombatHUDFloatie_Init_Patch { - + public static class CombatHUDFloatie_Init_Patch + { + public static bool Prepare() => Mod.Config.Fixes.BuildingDamageColorChange; - - public static void Postfix(CombatHUDFloatie __instance) { + + public static void Postfix(CombatHUDFloatie __instance) + { CombatHUDFloatieAnchor anchor = __instance.GetComponentInParent(); - if (anchor.DisplayedActor == null) { + if (anchor.DisplayedActor == null) + { __instance.floatieText.color = Color.blue * Color.white; } } diff --git a/IRTweaks/IRTweaks/Modules/Combat/ScaleObjectiveBuildingHealth.cs b/IRTweaks/IRTweaks/Modules/Combat/ScaleObjectiveBuildingHealth.cs index 8a404ae..f1e0228 100644 --- a/IRTweaks/IRTweaks/Modules/Combat/ScaleObjectiveBuildingHealth.cs +++ b/IRTweaks/IRTweaks/Modules/Combat/ScaleObjectiveBuildingHealth.cs @@ -5,40 +5,9 @@ using IRBTModUtils.Extension; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace IRTweaks.Modules.Combat { - //[HarmonyPatch(typeof(BattleTech.Building), "InitStats")] - //static class ScaleObjectiveBuildingStructure_Building_InitStats - //{ - // static bool Prepare => Mod.Config.Fixes.ScaleObjectiveBuildingStructure; - - // static void Postfix(BattleTech.Building __instance, bool ___isObjectiveTarget) - // { - - // //float adjustedStruct = (float)Math.Floor((__instance.CurrentStructure * scale.Multi) + scale.Mod); - // //Mod.Log.Info?.Write($" -- adjustedStructure: {adjustedStruct} = ( currentStruct: {__instance.CurrentStructure} x scaleMulti: {scale.Multi} ) + scaleMod: {scale.Mod}"); - // //__instance.StatCollection.ModifyStat("IRTweaks", -1, ModStats.HBS_Building_Structure, StatCollection.StatOperation.Set, adjustedStruct); - // //Traverse startingStructT = Traverse.Create(__instance).Property("StartingStructure"); - // //startingStructT.SetValue(adjustedStruct); - - // //Mod.Log.Info?.Write($"Evaluating building: {__instance.DistinctId()} for structure scaling."); - // //if (___isObjectiveTarget) - // //{ - - // //} - // //else - // //{ - // // Mod.Log.Info?.Write($" -- building is not objective target, it will not be scaled."); - // //} - - - // } - - //} [HarmonyPatch(typeof(TurnDirector), "OnInitializeContractComplete")] public static class ScaleObjectiveBuildingStructure_TurnDirector_OnInitializeContractComplete diff --git a/IRTweaks/IRTweaks/Modules/UI/BulkScrapping.cs b/IRTweaks/IRTweaks/Modules/UI/BulkScrapping.cs new file mode 100644 index 0000000..8b324a3 --- /dev/null +++ b/IRTweaks/IRTweaks/Modules/UI/BulkScrapping.cs @@ -0,0 +1,179 @@ +using BattleTech; +using BattleTech.UI; +using Harmony; +using HBS; +using Localize; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace IRTweaks.Modules.UI +{ + public static class ScrapHelper + { + public static void BuildScrapAllDialog(List widgetInventory, float scrapPartModifier, string title, Action confirmAction) + { + List activeItems = widgetInventory + .Where(x => x.GameObject.activeSelf) + .OfType() + .ToList(); + + int cbills = ScrapHelper.CalculateTotalScrap(activeItems, scrapPartModifier); + string cbillStr = SimGameState.GetCBillString(cbills); + + + string descLT = new Text(Mod.LocalizedText.Dialog[ModText.DT_Desc_ScrapAll], new object[] { cbillStr }).ToString(); + string cancelLT = new Text(Mod.LocalizedText.Dialog[ModText.DT_Button_Cancel]).ToString(); + string scrapLT = new Text(Mod.LocalizedText.Dialog[ModText.DT_Button_Scrap]).ToString(); + GenericPopupBuilder.Create(title, descLT) + .AddButton(cancelLT) + .AddButton(scrapLT, confirmAction) + .CancelOnEscape() + .AddFader(LazySingletonBehavior.Instance.UILookAndColorConstants.PopupBackfill) + .Render(); + } + + public static void ScrapAllActive(List widgetInventory) + { + List activeItems = widgetInventory + .Where(x => x.GameObject.activeSelf) + .OfType() + .ToList(); + + MechBayPanel mechBayPanel = LazySingletonBehavior.Instance.GetOrCreateUIModule(); + + foreach (MechBayChassisUnitElement item in activeItems) + { + // parts 0 + max 0 = one unit + int fullMechs = (item.PartsCount == 0 && item.PartsMax == 0) ? + 1 : (int)Math.Floor((double)item.PartsCount / item.PartsMax); + int partsCount = item.PartsCount - fullMechs; + + for (int i = 0; i < fullMechs; i++) + { + mechBayPanel.Sim.ScrapInactiveMech(item.ChassisDef.Description.Id, pay: true); + } + + for (int i = 0; i < partsCount; i++) + { + mechBayPanel.Sim.ScrapMechPart(item.ChassisDef.Description.Id, 1f, item.ChassisDef.MechPartMax, pay: true); + } + + mechBayPanel.RefreshData(resetFilters: true); + mechBayPanel.SelectChassis(null); + } + } + + public static int CalculateTotalScrap(List activeChassis, float scrapPartModifier) + { + float total = 0; + foreach (MechBayChassisUnitElement item in activeChassis) + { + Mod.Log.Info?.Write($"Part : {item.ChassisDef.Description.Name} {item.PartsCount} partsCounts with {item.PartsMax} partsMax"); + // parts 0 + max 0 = one unit + int fullMechs = (item.PartsCount == 0 && item.PartsMax == 0) ? + 1 : (int)Math.Floor((double)item.PartsCount / item.PartsMax); + int partsCount = item.PartsCount - fullMechs; + float partsFrac = item.PartsMax != 0 ? partsCount * (1f / item.PartsMax) : 0; + float partsMulti = fullMechs + partsFrac; + Mod.Log.Info?.Write($" -- {fullMechs} fullMechs, {partsCount} parts => {partsFrac} partsFrac, for partsMulti: {partsMulti}"); + + int perPartScrap = Mathf.RoundToInt((float)item.ChassisDef.Description.Cost * scrapPartModifier); + int totalScrapForChassis = (int)Math.Floor(perPartScrap * partsMulti); + Mod.Log.Info?.Write($" -- perPartScrap: {perPartScrap} x partsMulti: {partsMulti} => totalScrapForChassis: {totalScrapForChassis}"); + + total += totalScrapForChassis; + } + + int cbills = (int)Math.Ceiling(total); + + return cbills; + } + } + + [HarmonyPatch(typeof(MechBayMechStorageWidget), "Filter_WeightAll")] + static class BulkScrapping_MechBayMechStorageWidget_Filter_WeightAll + { + static bool Prepare => Mod.Config.Fixes.BulkScrapping; + + static void Postfix(MechBayMechStorageWidget __instance, List ___inventory) + { + if (___inventory != null && ___inventory.Count > 0 && + Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)) + { + string titleLT = new Text(Mod.LocalizedText.Dialog[ModText.DT_Title_ScrapAll]).ToString(); + ScrapHelper.BuildScrapAllDialog(___inventory, __instance.Sim.Constants.Finances.MechScrapModifier, titleLT, + delegate { ScrapHelper.ScrapAllActive(___inventory); }); + } + } + } + + [HarmonyPatch(typeof(MechBayMechStorageWidget), "Filter_WeightAssault")] + static class BulkScrapping_MechBayMechStorageWidget_Filter_WeightAssault + { + static bool Prepare => Mod.Config.Fixes.BulkScrapping; + + static void Postfix(MechBayMechStorageWidget __instance, List ___inventory) + { + if (___inventory != null && ___inventory.Count > 0 && + Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)) + { + string titleLT = new Text(Mod.LocalizedText.Dialog[ModText.DT_Title_ScrapAssaults]).ToString(); + ScrapHelper.BuildScrapAllDialog(___inventory, __instance.Sim.Constants.Finances.MechScrapModifier, titleLT, + delegate { ScrapHelper.ScrapAllActive(___inventory); }); + } + } + } + + [HarmonyPatch(typeof(MechBayMechStorageWidget), "Filter_WeightHeavy")] + static class BulkScrapping_MechBayMechStorageWidget_Filter_WeightHeavy + { + static bool Prepare => Mod.Config.Fixes.BulkScrapping; + + static void Postfix(MechBayMechStorageWidget __instance, List ___inventory) + { + if (___inventory != null && ___inventory.Count > 0 && + Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)) + { + string titleLT = new Text(Mod.LocalizedText.Dialog[ModText.DT_Title_ScrapHeavies]).ToString(); + ScrapHelper.BuildScrapAllDialog(___inventory, __instance.Sim.Constants.Finances.MechScrapModifier, titleLT, + delegate { ScrapHelper.ScrapAllActive(___inventory); }); + } + } + } + + [HarmonyPatch(typeof(MechBayMechStorageWidget), "Filter_WeightLight")] + static class BulkScrapping_MechBayMechStorageWidget_Filter_WeightLight + { + static bool Prepare => Mod.Config.Fixes.BulkScrapping; + + static void Postfix(MechBayMechStorageWidget __instance, List ___inventory) + { + if (___inventory != null && ___inventory.Count > 0 && + Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)) + { + string titleLT = new Text(Mod.LocalizedText.Dialog[ModText.DT_Title_ScrapLights]).ToString(); + ScrapHelper.BuildScrapAllDialog(___inventory, __instance.Sim.Constants.Finances.MechScrapModifier, titleLT, + delegate { ScrapHelper.ScrapAllActive(___inventory); }); + } + } + } + + [HarmonyPatch(typeof(MechBayMechStorageWidget), "Filter_WeightMedium")] + static class BulkScrapping_MechBayMechStorageWidget_Filter_WeightMedium + { + static bool Prepare => Mod.Config.Fixes.BulkScrapping; + + static void Postfix(MechBayMechStorageWidget __instance, List ___inventory) + { + if (___inventory != null && ___inventory.Count > 0 && + Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt)) + { + string titleLT = new Text(Mod.LocalizedText.Dialog[ModText.DT_Title_ScrapMediums]).ToString(); + ScrapHelper.BuildScrapAllDialog(___inventory, __instance.Sim.Constants.Finances.MechScrapModifier, titleLT, + delegate { ScrapHelper.ScrapAllActive(___inventory); }); + } + } + } +} diff --git a/IRTweaks/IRTweaks/Modules/UI/WeaponTooltips.cs b/IRTweaks/IRTweaks/Modules/UI/WeaponTooltips.cs index 2dfe702..9fea8ab 100644 --- a/IRTweaks/IRTweaks/Modules/UI/WeaponTooltips.cs +++ b/IRTweaks/IRTweaks/Modules/UI/WeaponTooltips.cs @@ -1,16 +1,23 @@ using BattleTech; using BattleTech.UI.Tooltips; using CustAmmoCategories; +using Harmony; using TMPro; using UnityEngine; using UnityEngine.UI; -namespace IRTweaks.Modules.UI { - +namespace IRTweaks.Modules.UI +{ + // Update the tooltip to distinguish between different weapon types, and make CAC mannerisms clearer - public static class WeaponTooltips { - public static void TooltipPrefab_Weapon_SetData_Postfix(TooltipPrefab_Weapon __instance, object data, - TextMeshProUGUI ___rangeType, TextMeshProUGUI ___damage) { + [HarmonyPatch(typeof(TooltipPrefab_Weapon), "SetData")] + static class WeaponTooltips_TooltipPrefab_Weapon_SetData + { + static bool Prepare => Mod.Config.Fixes.WeaponTooltip; + + static void Postfix(TooltipPrefab_Weapon __instance, object data, + TextMeshProUGUI ___rangeType, TextMeshProUGUI ___damage) + { Mod.Log.Debug?.Write("TP_W:SD entered."); ___rangeType.enabled = false; diff --git a/IRTweaks/IRTweaks/Modules/UIModule.cs b/IRTweaks/IRTweaks/Modules/UIModule.cs index 18351a6..0678931 100644 --- a/IRTweaks/IRTweaks/Modules/UIModule.cs +++ b/IRTweaks/IRTweaks/Modules/UIModule.cs @@ -6,15 +6,21 @@ using System; using System.Reflection; -namespace IRTweaks.Modules.Tooltip { - public static class UIFixes { +namespace IRTweaks.Modules.Tooltip +{ + public static class UIFixes + { static bool Initialized = false; - public static void InitModule(HarmonyInstance harmony) { - if (!Initialized) { - try { + public static void InitModule(HarmonyInstance harmony) + { + if (!Initialized) + { + try + { // Updates the purchase and selling dialogs to allow multiple items to be purchased and sold at once - if (Mod.Config.Fixes.BulkPurchasing) { + if (Mod.Config.Fixes.BulkPurchasing) + { Mod.Log.Info?.Write("Activating Fix: BulkPurchasing"); MethodInfo refreshMI = AccessTools.Method(typeof(SG_Stores_MultiPurchasePopup), "Refresh"); HarmonyMethod mpp_R_Post = new HarmonyMethod(typeof(StoreQuantities), "MultiPurchasePopup_Refresh_Postfix"); @@ -30,7 +36,8 @@ public static void InitModule(HarmonyInstance harmony) { } // Enable the CombatLog - if (Mod.Config.Fixes.CombatLog) { + if (Mod.Config.Fixes.CombatLog) + { Mod.Log.Info?.Write("Activating Fix: CombatLog"); MethodInfo combatHUD_Init_MI = AccessTools.Method(typeof(CombatHUD), "Init", new Type[] { typeof(CombatGameState) }); HarmonyMethod cl_chud_i_post = new HarmonyMethod(typeof(CombatLog), "CombatHUD_Init_Postfix"); @@ -74,7 +81,8 @@ public static void InitModule(HarmonyInstance harmony) { Mod.Log.Info?.Write("Activating Fix: DisableCombatRestart"); // Makes the main menu a smoother as there are fewer - if (Mod.Config.Fixes.StreamlinedMainMenu) { + if (Mod.Config.Fixes.StreamlinedMainMenu) + { Mod.Log.Info?.Write("Activating Fix: StreamlinedMainMenu"); MethodInfo sgnb_rftp_mi = AccessTools.Method(typeof(SGNavigationButton), "ResetFlyoutsToPrefab"); @@ -100,14 +108,12 @@ public static void InitModule(HarmonyInstance harmony) { } // Update the weapon tooltip to support CAC behaviors - if (Mod.Config.Fixes.WeaponTooltip) { + if (Mod.Config.Fixes.WeaponTooltip) Mod.Log.Info?.Write("Activating Fix: WeaponTooltip"); - MethodInfo tooltipPrefab_Weapon_SetData = AccessTools.Method(typeof(TooltipPrefab_Weapon), "SetData"); - HarmonyMethod tm_tp_w_sd_post = new HarmonyMethod(typeof(WeaponTooltips), "TooltipPrefab_Weapon_SetData_Postfix"); - harmony.Patch(tooltipPrefab_Weapon_SetData, null, tm_tp_w_sd_post, null); - } - } catch (Exception e) { + } + catch (Exception e) + { Mod.Log.Error?.Write($"Failed to load patches due to: {e.Message}"); Mod.Log.Error?.Write(e.StackTrace); Mod.Log.Error?.Write(e.ToString()); diff --git a/mod_localized_text.json b/mod_localized_text.json index 40f57e8..99476e2 100644 --- a/mod_localized_text.json +++ b/mod_localized_text.json @@ -1,4 +1,18 @@ { + + "Dialog" : { + "SCRAP_ALL_TITLE" : "SCRAP ALL IN STORAGE", + "SCRAP_ALL_ASSAULT" : "SCRAP ASSAULTS IN STORAGE", + "SCRAP_ALL_HEAVY" : "SCRAP HEAVIES IN STORAGE", + "SCRAP_ALL_LIGHT" : "SCRAP LIGHTS IN STORAGE", + "SCRAP_ALL_MEDIUM" : "SCRAP MEDIUMS IN STORAGE", + + "SCRAP_ALL_DESC" : "This will scrap units currently in storage, gaining {0} c-bills. This action cannot be reversed, you will need to load an earlier save. Are you sure?", + + "BUTTON_CANCEL" : "CANCEL", + "BUTTON_SCRAP" : "SCRAP" + }, + "Floaties": { "INJURY_RESIST": "INJURY RESISTED!" },