diff --git a/ElectronicObserver.Core/Types/Serialization/EquipmentUpgrade/UpgradeCostDataEqualityComparer.cs b/ElectronicObserver.Core/Types/Serialization/EquipmentUpgrade/UpgradeCostDataEqualityComparer.cs new file mode 100644 index 000000000..1956a5727 --- /dev/null +++ b/ElectronicObserver.Core/Types/Serialization/EquipmentUpgrade/UpgradeCostDataEqualityComparer.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace ElectronicObserver.Core.Types.Serialization.EquipmentUpgrade; + +/// +/// This equality comparer is used to group upgrade data based on the cost of levels 0 -> 5 and 6 -> max +/// Conversion & extra costs are ignored +/// +public class UpgradeCostDataEqualityComparer : IEqualityComparer +{ + public bool Equals(EquipmentUpgradeImprovementModel? x, EquipmentUpgradeImprovementModel? y) + { + if (ReferenceEquals(x, y)) + return true; + + if (x is null || y is null) + return false; + + return Equals(x.Costs, y.Costs); + } + + private bool Equals(EquipmentUpgradeImprovementCost? x, EquipmentUpgradeImprovementCost? y) + { + if (ReferenceEquals(x, y)) + return true; + + if (x is null || y is null) + return false; + + if (x.Fuel != y.Fuel) return false; + if (x.Ammo != y.Ammo) return false; + if (x.Steel != y.Steel) return false; + if (x.Bauxite != y.Bauxite) return false; + + if (!Equals(x.Cost0To5, y.Cost0To5)) return false; + if (!Equals(x.Cost6To9, y.Cost6To9)) return false; + + return true; + } + + private bool Equals(EquipmentUpgradeImprovementCostDetail? x, EquipmentUpgradeImprovementCostDetail? y) + { + if (ReferenceEquals(x, y)) + return true; + + if (x is null || y is null) + return false; + + if (x.DevmatCost != y.DevmatCost) return false; + if (x.SliderDevmatCost != y.SliderDevmatCost) return false; + if (x.ImproveMatCost != y.ImproveMatCost) return false; + if (x.SliderImproveMatCost != y.SliderImproveMatCost) return false; + + foreach (EquipmentUpgradeImprovementCostItemDetail costItem in x.ConsumableDetail) + { + EquipmentUpgradeImprovementCostItemDetail? matchingCostItem = y.ConsumableDetail.Find(c => c.Id == costItem.Id); + + if (matchingCostItem is null || costItem.Count != matchingCostItem.Count) + return false; + } + + foreach (EquipmentUpgradeImprovementCostItemDetail costItem in x.EquipmentDetail) + { + EquipmentUpgradeImprovementCostItemDetail? matchingCostItem = y.EquipmentDetail.Find(c => c.Id == costItem.Id); + + if (matchingCostItem is null || costItem.Count != matchingCostItem.Count) + return false; + } + + return true; + } + + public int GetHashCode(EquipmentUpgradeImprovementModel obj) => GetHashCode(obj.Costs); + + private int GetHashCode(EquipmentUpgradeImprovementCost cost) + { + HashCode hash = new(); + + hash.Add(cost.Fuel); + hash.Add(cost.Ammo); + hash.Add(cost.Steel); + hash.Add(cost.Bauxite); + + hash.Add(GetHashCode(cost.Cost0To5)); + hash.Add(GetHashCode(cost.Cost6To9)); + + return hash.ToHashCode(); + } + + private int GetHashCode(EquipmentUpgradeImprovementCostDetail cost) + { + HashCode hash = new(); + + hash.Add(cost.DevmatCost); + hash.Add(cost.SliderDevmatCost); + hash.Add(cost.ImproveMatCost); + hash.Add(cost.SliderImproveMatCost); + + foreach (EquipmentUpgradeImprovementCostItemDetail costItem in cost.ConsumableDetail.OrderBy(c => c.Id)) + { + hash.Add(costItem.Id); + hash.Add(costItem.Count); + } + + foreach (EquipmentUpgradeImprovementCostItemDetail costItem in cost.EquipmentDetail.OrderBy(e => e.Id)) + { + hash.Add(costItem.Id); + hash.Add(costItem.Count); + } + + return hash.ToHashCode(); + } +} diff --git a/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/DialogAlbumMasterEquipmentWpf.xaml b/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/DialogAlbumMasterEquipmentWpf.xaml index a5334eb72..5048e1409 100644 --- a/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/DialogAlbumMasterEquipmentWpf.xaml +++ b/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/DialogAlbumMasterEquipmentWpf.xaml @@ -179,7 +179,12 @@ - + + + + + + @@ -367,7 +372,7 @@ /> - + @@ -638,25 +643,25 @@ - + - + - + - + @@ -673,9 +678,47 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeControl.xaml b/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeControl.xaml index d565567ad..f4189c8c9 100644 --- a/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeControl.xaml +++ b/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeControl.xaml @@ -7,13 +7,13 @@ xmlns:helpers="clr-namespace:ElectronicObserver.Window.Tools.EquipmentUpgradePlanner.Helpers" xmlns:local="clr-namespace:ElectronicObserver.Window.Tools.DialogAlbumMasterEquipment.EquipmentUpgrade" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - d:DataContext="{d:DesignInstance local:AlbumMasterEquipmentUpgradeViewModel}" + d:DataContext="{d:DesignInstance local:AlbumMasterEquipmentUpgradeGroupViewModel}" d:DesignHeight="450" d:DesignWidth="800" mc:Ignorable="d" > - + @@ -83,31 +83,9 @@ - - - - - - - - - - - + /// Equipment upgrade cost, its the first cost found for this equipment so it's accurate for fuel, ammo, ... and devmats/screws for 0 -> 9 upgrades + /// + public EquipmentUpgradeImprovementCost EquipmentUpgradeCost { get; private set; } = new(); + + public List RequiredItemsPerLevel { get; set; } = []; + + public List ConversionViewModel { get; private set; } = []; + + public List Helpers { get; private set; } = []; + + public AlbumMasterEquipmentUpgradeTranslationViewModel EquipmentUpgradeTranslation { get; } + + public List Models { get; } + + public AlbumMasterEquipmentUpgradeGroupViewModel(List improvements, AlbumMasterEquipmentUpgradeTranslationViewModel translations, IEquipmentDataMaster equipment) + { + Models = improvements; + EquipmentUpgradeTranslation = translations; + Equipment = equipment; + + LoadUpgradeData(); + } + + private void LoadUpgradeData() + { + EquipmentUpgradeImprovementModel? firstImprovement = Models.FirstOrDefault(); + + if (firstImprovement is null) return; + + EquipmentUpgradeCost = firstImprovement.Costs; + + Helpers = Models + .SelectMany(improvement => improvement.Helpers) + .Select(helperGroup => new EquipmentUpgradeHelpersViewModel(helperGroup)) + .ToList(); + + InitializeCostPerLevel(); + + ConversionViewModel = Models + .Where(improvement => improvement.ConversionData is not null) + .Where(improvement => improvement.Costs.CostMax is not null) + .Select(improvement => new EquipmentUpgradeConversionViewModel(improvement)) + .ToList(); + } + + private void InitializeCostPerLevel() + { + RequiredItemsPerLevel = EquipmentUpgradeCost + .GetCostPerLevelRange() + .Where(range => range.StartLevel != UpgradeLevel.Conversion) + .Select(range => new AlbumMasterEquipmentUpgradeLevelViewModel(range)) + .ToList(); + } + + public void UnsubscribeFromApis() + { + ConversionViewModel.ForEach(viewModel => viewModel.UnsubscribeFromApis()); + Helpers.ForEach(viewModel => viewModel.UnsubscribeFromApis()); + RequiredItemsPerLevel.ForEach(viewModel => viewModel.UnsubscribeFromApis()); + } +} diff --git a/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeViewModelProxy.cs b/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeGroupViewModelProxy.cs similarity index 52% rename from ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeViewModelProxy.cs rename to ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeGroupViewModelProxy.cs index 2ecf0f702..10027e7d4 100644 --- a/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeViewModelProxy.cs +++ b/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeGroupViewModelProxy.cs @@ -2,6 +2,6 @@ namespace ElectronicObserver.Window.Tools.DialogAlbumMasterEquipment.EquipmentUpgrade; -public class AlbumMasterEquipmentUpgradeViewModelProxy : BindingProxy +public class AlbumMasterEquipmentUpgradeGroupViewModelProxy : BindingProxy { } diff --git a/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeViewModel.cs b/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeViewModel.cs index 65143a558..e6217fa39 100644 --- a/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeViewModel.cs +++ b/ElectronicObserver/Window/Tools/DialogAlbumMasterEquipment/EquipmentUpgrade/AlbumMasterEquipmentUpgradeViewModel.cs @@ -5,28 +5,18 @@ using ElectronicObserver.Core.Types.Serialization.EquipmentUpgrade; using ElectronicObserver.Data; using ElectronicObserver.Data.Translation; -using ElectronicObserver.Utility.Data; -using ElectronicObserver.Window.Tools.EquipmentUpgradePlanner.Helpers; namespace ElectronicObserver.Window.Tools.DialogAlbumMasterEquipment.EquipmentUpgrade; public class AlbumMasterEquipmentUpgradeViewModel { - public EquipmentUpgradeDataModel? UpgradeData { get; private set; } - public IEquipmentDataMaster Equipment { get; } + public int Fuel { get; set; } + public int Ammo { get; set; } + public int Steel { get; set; } + public int Bauxite { get; set; } - public bool CanBeUpgraded => UpgradeData?.Improvement.FirstOrDefault() is not null; - - /// - /// Equipment upgrade cost, its the first cost found for this equipment so it's accurate for fuel, ammo, ... and devmats/screws for 0 -> 9 upgrades - /// - public EquipmentUpgradeImprovementCost EquipmentUpgradeCost { get; private set; } = new(); - - public List RequiredItemsPerLevel { get; set; } = []; - - public List ConversionViewModel { get; private set; } = new(); - - public List Helpers { get; private set; } = new(); + public List UpgradeViewModels { get; private set; } = []; + private IEquipmentDataMaster Equipment { get; } public AlbumMasterEquipmentUpgradeTranslationViewModel EquipmentUpgradeTranslation { get; } @@ -41,44 +31,39 @@ public AlbumMasterEquipmentUpgradeViewModel(IEquipmentDataMaster equipment) private void LoadUpgradeData() { EquipmentUpgradeData upgradeData = KCDatabase.Instance.Translation.EquipmentUpgrade; - UpgradeData = upgradeData.UpgradeList.FirstOrDefault(upgrade => upgrade.EquipmentId == Equipment.ID); + EquipmentUpgradeDataModel? data = upgradeData.UpgradeList.FirstOrDefault(upgrade => upgrade.EquipmentId == Equipment.ID); - if (UpgradeData is null) return; + if (data is null) return; - EquipmentUpgradeImprovementModel? firstImprovement = UpgradeData.Improvement.FirstOrDefault(); + EquipmentUpgradeImprovementModel? firstImprovement = data.Improvement.FirstOrDefault(); if (firstImprovement is null) return; - EquipmentUpgradeCost = firstImprovement.Costs; - - Helpers = UpgradeData.Improvement - .SelectMany(improvement => improvement.Helpers) - .Select(helperGroup => new EquipmentUpgradeHelpersViewModel(helperGroup)) - .ToList(); - - InitializeCostPerLevel(); - - ConversionViewModel = UpgradeData - .Improvement - .Where(improvement => improvement.ConversionData is not null) - .Where(improvement => improvement.Costs.CostMax is not null) - .Select(improvement => new EquipmentUpgradeConversionViewModel(improvement)) - .ToList(); - } - - private void InitializeCostPerLevel() - { - RequiredItemsPerLevel = EquipmentUpgradeCost - .GetCostPerLevelRange() - .Where(range => range.StartLevel != UpgradeLevel.Conversion) - .Select(range => new AlbumMasterEquipmentUpgradeLevelViewModel(range)) - .ToList(); + Fuel = firstImprovement.Costs.Fuel; + Ammo = firstImprovement.Costs.Ammo; + Steel = firstImprovement.Costs.Steel; + Bauxite = firstImprovement.Costs.Bauxite; + + List conversions = data.Improvement.Select(i => i.ConversionData?.IdEquipmentAfter).OfType().ToList(); + + if (conversions.Count != conversions.Distinct().Count()) + { + // Special case : 12.7cm連装砲A型 conversion cost is different depending on ship + UpgradeViewModels = data.Improvement + .Select(improvement => new AlbumMasterEquipmentUpgradeGroupViewModel([improvement], EquipmentUpgradeTranslation, Equipment)) + .ToList(); + } + else + { + UpgradeViewModels = data.Improvement + .GroupBy(improvement => improvement, new UpgradeCostDataEqualityComparer()) + .Select(group => new AlbumMasterEquipmentUpgradeGroupViewModel(group.ToList(), EquipmentUpgradeTranslation, Equipment)) + .ToList(); + } } public void UnsubscribeFromApis() { - ConversionViewModel.ForEach(viewModel => viewModel.UnsubscribeFromApis()); - Helpers.ForEach(viewModel => viewModel.UnsubscribeFromApis()); - RequiredItemsPerLevel.ForEach(viewModel => viewModel.UnsubscribeFromApis()); + UpgradeViewModels.ForEach(vm => vm.UnsubscribeFromApis()); } }