From 18afbffbcc1aa2fed7164733033416e1c662eb57 Mon Sep 17 00:00:00 2001 From: mfkvfhpdx Date: Mon, 4 May 2026 08:03:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9D=90=E6=96=99=E7=BB=9F=E8=AE=A1=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=91=A8=E6=9C=AC=E6=9D=90=E6=96=99=E8=BD=AC=E5=8C=96?= =?UTF-8?q?=E5=90=8E=E7=9A=84=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Snap.Hutao/Core/Setting/SettingKeys.cs | 1 + .../Resource/Localization/SH.en.resx | 3 + .../Snap.Hutao/Resource/Localization/SH.resx | 3 + .../Cultivation/CultivationMetadataContext.cs | 3 + .../Service/Cultivation/CultivationService.cs | 4 + .../CultivationStatisticsMergeOptions.cs | 5 +- ...tivationStatisticsWeeklyBossInterchange.cs | 109 ++++++++++++++ .../ICultivationMetadataContext.cs | 3 +- ...klyBossMaterialInterchangeGroupsBuilder.cs | 138 ++++++++++++++++++ ...eklyBossMaterialInterchangeGroupsSource.cs | 15 ++ .../MetadataServiceContextExtension.cs | 5 + ...dataServiceImmutableDictionaryExtension.cs | 13 ++ .../UI/Xaml/View/Page/CultivationPage.xaml | 6 + .../Cultivation/CultivationViewModel.cs | 7 +- .../Cultivation/StatisticsCultivateItem.cs | 19 ++- 15 files changed, 325 insertions(+), 9 deletions(-) create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationStatisticsWeeklyBossInterchange.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Cultivation/WeeklyBossMaterialInterchangeGroupsBuilder.cs create mode 100644 src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataWeeklyBossMaterialInterchangeGroupsSource.cs diff --git a/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs b/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs index 1b46568..7e65fd9 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/Setting/SettingKeys.cs @@ -76,6 +76,7 @@ internal static class SettingKeys public const string ResinStatisticsSelectedDropDistribution = "Snap::Hutao::Cultivation::ResinStatistics::DropDistribution"; public const string CultivationStatisticsMergeUpgradeMaterials = "Snap::Hutao::Cultivation::Statistics::MergeUpgradeMaterials"; public const string CultivationStatisticsTalentSynthCritTenPercent = "Snap::Hutao::Cultivation::Statistics::TalentSynthCritTenPercent"; + public const string CultivationStatisticsWeeklyBossMaterialInterchange = "Snap::Hutao::Cultivation::Statistics::WeeklyBossMaterialInterchange"; // GachaLog public const string IsEmptyHistoryWishVisible = "Snap::Hutao::GachaLog::HistoryWish::EmptyVisible"; diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx index ee96adc..4b1c543 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.en.resx @@ -2429,6 +2429,9 @@ Space Available: {2} Character talent (10%) + + Weekly boss material interchange + Resin Estimation diff --git a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx index bffdee1..e8536bd 100644 --- a/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx +++ b/src/Snap.Hutao/Snap.Hutao/Resource/Localization/SH.resx @@ -2480,6 +2480,9 @@ 角色天赋(10%) + + 周本材料转化 + 树脂预估 diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationMetadataContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationMetadataContext.cs index 3ff52a3..353d080 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationMetadataContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationMetadataContext.cs @@ -23,6 +23,9 @@ internal class CultivationMetadataContext : ICultivationMetadataContext public ImmutableDictionary ResultMaterialIdCombineMap { get; set; } = default!; + public ImmutableArray> WeeklyBossMaterialInterchangeGroups { get; set; } + = ImmutableArray>.Empty; + public Item GetAvatarItem(AvatarId avatarId) { return this.GetAvatar(avatarId).GetOrCreateItem(); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs index b0a0e13..47c97f2 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationService.cs @@ -152,6 +152,10 @@ internal sealed partial class CultivationService : ICultivationService } CultivationStatisticsSurplusMerge.Apply(resultItems, context, mergeOptions); + CultivationStatisticsWeeklyBossInterchange.Apply( + resultItems, + context.WeeklyBossMaterialInterchangeGroups, + mergeOptions.WeeklyBossMaterialInterchange); ApplyStatisticsConsumerMenuLines(resultItems, projectId, context, cultivationRepository, token); return new(resultItems); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationStatisticsMergeOptions.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationStatisticsMergeOptions.cs index 48d2aa7..d0c5ccb 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationStatisticsMergeOptions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationStatisticsMergeOptions.cs @@ -3,4 +3,7 @@ namespace Snap.Hutao.Service.Cultivation; -internal readonly record struct CultivationStatisticsMergeOptions(bool MergeUpgradeMaterials, bool TalentSynthCritTenPercent); +internal readonly record struct CultivationStatisticsMergeOptions( + bool MergeUpgradeMaterials, + bool TalentSynthCritTenPercent, + bool WeeklyBossMaterialInterchange); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationStatisticsWeeklyBossInterchange.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationStatisticsWeeklyBossInterchange.cs new file mode 100644 index 0000000..6bdf685 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/CultivationStatisticsWeeklyBossInterchange.cs @@ -0,0 +1,109 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Primitive; +using Snap.Hutao.ViewModel.Cultivation; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace Snap.Hutao.Service.Cultivation; + +/// +/// 材料统计:同一周本 Boss 材料池内,将超出需求的虚拟持有量 1:1 调配给池内缺口(不计异梦溶媒消耗)。 +/// +internal static class CultivationStatisticsWeeklyBossInterchange +{ + public static void Apply( + Dictionary items, + ImmutableArray> interchangeGroups, + bool enabled) + { + if (!enabled || interchangeGroups.IsDefault || interchangeGroups.IsEmpty) + { + return; + } + + foreach (ImmutableArray group in interchangeGroups) + { + ApplySingleGroup(items, group); + } + } + + private static void ApplySingleGroup(Dictionary items, ImmutableArray group) + { + List poolIds = []; + foreach (MaterialId mid in group) + { + uint id = mid; + if (items.ContainsKey(id)) + { + poolIds.Add(id); + } + } + + if (poolIds.Count < 2) + { + return; + } + + Dictionary virt = new(poolIds.Count); + foreach (uint id in poolIds) + { + StatisticsCultivateItem it = items[id]; + virt[id] = it.MergeAdjustedCurrent ?? it.Current; + } + + while (true) + { + uint? donor = null; + uint maxSurplus = 0U; + foreach (uint id in poolIds) + { + uint v = virt[id]; + uint need = items[id].Count; + if (v > need && v - need > maxSurplus) + { + maxSurplus = v - need; + donor = id; + } + } + + uint? receiver = null; + uint maxDeficit = 0U; + foreach (uint id in poolIds) + { + if (id == donor) + { + continue; + } + + uint v = virt[id]; + uint need = items[id].Count; + if (v < need && need - v > maxDeficit) + { + maxDeficit = need - v; + receiver = id; + } + } + + if (donor is null || receiver is null || maxSurplus is 0U || maxDeficit is 0U) + { + break; + } + + virt[donor.Value]--; + virt[receiver.Value]++; + } + + foreach (uint id in poolIds) + { + StatisticsCultivateItem it = items[id]; + uint baseline = it.MergeAdjustedCurrent ?? it.Current; + uint finalV = virt[id]; + if (finalV != baseline) + { + it.WeeklyBossInterchangeAdjustedCurrent = finalV; + } + } + } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationMetadataContext.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationMetadataContext.cs index d2abe0f..26e5f76 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationMetadataContext.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/ICultivationMetadataContext.cs @@ -14,7 +14,8 @@ internal interface ICultivationMetadataContext : IMetadataContext, IMetadataDictionaryIdMaterialSource, IMetadataDictionaryIdAvatarSource, IMetadataDictionaryIdWeaponSource, - IMetadataDictionaryResultMaterialIdCombineSource + IMetadataDictionaryResultMaterialIdCombineSource, + IMetadataWeeklyBossMaterialInterchangeGroupsSource { Item GetAvatarItem(AvatarId avatarId); diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/WeeklyBossMaterialInterchangeGroupsBuilder.cs b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/WeeklyBossMaterialInterchangeGroupsBuilder.cs new file mode 100644 index 0000000..86c8ab2 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Cultivation/WeeklyBossMaterialInterchangeGroupsBuilder.cs @@ -0,0 +1,138 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Intrinsic; +using Snap.Hutao.Model.Metadata; +using Snap.Hutao.Model.Primitive; +using System.Collections.Generic; +using System.Collections.Immutable; + +namespace Snap.Hutao.Service.Cultivation; + +/// +/// 自 Combine 列表解析周本材料异梦转化互通组:配方为 Type=9、CONVERT、产物×1、材料为「异梦溶媒」+ 另一周本材料各×1。 +/// +internal static class WeeklyBossMaterialInterchangeGroupsBuilder +{ + /// 异梦溶媒 Id(转化消耗,统计虚拟调配时不扣溶媒,仅利用池内 1:1 等价)。 + private const uint DreamSolventMaterialId = 113021U; + + public static ImmutableArray> Build(ImmutableArray combines) + { + Dictionary> adjacency = []; + + foreach (Combine combine in combines) + { + if (combine.Type is not 9U) + { + continue; + } + + if (combine.RecipeType is not RecipeType.RECIPE_TYPE_CONVERT) + { + continue; + } + + if (combine.Materials.Length is not 2 || combine.Result.Count is not 1) + { + continue; + } + + MaterialId resultId = combine.Result.Id; + MaterialId? otherMaterial = null; + foreach (ref readonly IdCount m in combine.Materials.AsSpan()) + { + if (m.Id == DreamSolventMaterialId) + { + continue; + } + + if (m.Count is not 1) + { + otherMaterial = null; + break; + } + + otherMaterial = m.Id; + } + + if (otherMaterial is null || otherMaterial.Value == resultId) + { + continue; + } + + AddUndirectedEdge(adjacency, resultId, otherMaterial.Value); + } + + return ToComponents(adjacency); + } + + private static void AddUndirectedEdge(Dictionary> adjacency, MaterialId a, MaterialId b) + { + if (!adjacency.TryGetValue(a, out HashSet? setA)) + { + setA = []; + adjacency[a] = setA; + } + + if (!adjacency.TryGetValue(b, out HashSet? setB)) + { + setB = []; + adjacency[b] = setB; + } + + _ = setA.Add(b); + _ = setB.Add(a); + } + + private static ImmutableArray> ToComponents(Dictionary> adjacency) + { + if (adjacency.Count is 0) + { + return ImmutableArray>.Empty; + } + + HashSet visited = []; + ImmutableArray>.Builder groups = ImmutableArray.CreateBuilder>(); + + foreach (MaterialId start in adjacency.Keys) + { + if (visited.Contains(start)) + { + continue; + } + + List component = []; + Queue queue = new(); + queue.Enqueue(start); + visited.Add(start); + + while (queue.Count > 0) + { + MaterialId id = queue.Dequeue(); + component.Add(id); + + if (!adjacency.TryGetValue(id, out HashSet? neighbors)) + { + continue; + } + + foreach (MaterialId n in neighbors) + { + if (visited.Add(n)) + { + queue.Enqueue(n); + } + } + } + + if (component.Count >= 2) + { + component.Sort(MaterialIdComparer.Shared); + groups.Add(component.ToImmutableArray()); + } + } + + return groups.ToImmutable(); + } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataWeeklyBossMaterialInterchangeGroupsSource.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataWeeklyBossMaterialInterchangeGroupsSource.cs new file mode 100644 index 0000000..35adc15 --- /dev/null +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/IMetadataWeeklyBossMaterialInterchangeGroupsSource.cs @@ -0,0 +1,15 @@ +// Copyright (c) DGP Studio. All rights reserved. +// Licensed under the MIT license. + +using Snap.Hutao.Model.Primitive; +using System.Collections.Immutable; + +namespace Snap.Hutao.Service.Metadata.ContextAbstraction; + +/// +/// 周本 Boss 掉落材料「异梦转化」互通组(由 Combine 元数据解析)。 +/// +internal interface IMetadataWeeklyBossMaterialInterchangeGroupsSource : IMetadataContext +{ + ImmutableArray> WeeklyBossMaterialInterchangeGroups { get; set; } +} diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs index 62d7b28..6d21c38 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/ContextAbstraction/MetadataServiceContextExtension.cs @@ -211,6 +211,11 @@ internal static class MetadataServiceContextExtension { dictionaryResultMaterialIdCombineSource.ResultMaterialIdCombineMap = await metadataService.GetResultMaterialIdToCombineMapAsync(token).ConfigureAwait(false); } + + if (context is IMetadataWeeklyBossMaterialInterchangeGroupsSource weeklyBossInterchange) + { + weeklyBossInterchange.WeeklyBossMaterialInterchangeGroups = await metadataService.GetWeeklyBossMaterialInterchangeGroupsAsync(token).ConfigureAwait(false); + } } if (context is IMetadataSupportInitialization supportInitialization) diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataServiceImmutableDictionaryExtension.cs b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataServiceImmutableDictionaryExtension.cs index f7ced14..9485031 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataServiceImmutableDictionaryExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/Metadata/MetadataServiceImmutableDictionaryExtension.cs @@ -13,6 +13,7 @@ using Snap.Hutao.Model.Metadata.Reliquary; using Snap.Hutao.Model.Metadata.Tower; using Snap.Hutao.Model.Metadata.Weapon; using Snap.Hutao.Model.Primitive; +using Snap.Hutao.Service.Cultivation; using System.Collections.Immutable; namespace Snap.Hutao.Service.Metadata; @@ -229,6 +230,18 @@ internal static class MetadataServiceImmutableDictionaryExtension return result; } + public async ValueTask>> GetWeeklyBossMaterialInterchangeGroupsAsync(CancellationToken token = default) + { + string cacheKey = $"{nameof(MetadataService)}.Cache.{MetadataFileStrategies.Combine.Name}.WeeklyBossMaterialInterchangeGroups"; + ImmutableArray>? result = await metadataService.MemoryCache.GetOrCreateAsync(cacheKey, async entry => + { + ImmutableArray array = await metadataService.FromCacheOrFileAsync(MetadataFileStrategies.Combine, token).ConfigureAwait(false); + return WeeklyBossMaterialInterchangeGroupsBuilder.Build(array); + }).ConfigureAwait(false); + + return result ?? ImmutableArray>.Empty; + } + private ValueTask> FromCacheAsDictionaryAsync(MetadataFileStrategy strategy, CancellationToken token) where TKey : notnull where TValue : class, IDefaultIdentity diff --git a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/CultivationPage.xaml b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/CultivationPage.xaml index f0a6463..f32349c 100644 --- a/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/CultivationPage.xaml +++ b/src/Snap.Hutao/Snap.Hutao/UI/Xaml/View/Page/CultivationPage.xaml @@ -588,6 +588,12 @@ IsEnabled="{Binding MergeUpgradeMaterials}" Label="{shuxm:ResourceString Name=ViewPageCultivationTalentSynthCritTenPercentLabel}" Visibility="{Binding ElementName=MaterialListPivot, Path=SelectedItem.Tag, Converter={StaticResource MaterialListSelectedItemIsStatisticsViewConverter}}"/> + diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivationViewModel.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivationViewModel.cs index da96cf3..8cd2574 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivationViewModel.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/CultivationViewModel.cs @@ -77,6 +77,9 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel [ObservableProperty] public partial bool TalentSynthCritTenPercent { get; set; } = LocalSetting.Get(SettingKeys.CultivationStatisticsTalentSynthCritTenPercent, false); + [ObservableProperty] + public partial bool WeeklyBossMaterialInterchange { get; set; } = LocalSetting.Get(SettingKeys.CultivationStatisticsWeeklyBossMaterialInterchange, false); + [ObservableProperty] public partial ObservableCollection? StatisticsItems { get; set; } @@ -365,8 +368,10 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel bool merge = MergeUpgradeMaterials; bool talentCrit = merge && TalentSynthCritTenPercent; + bool weeklyBoss = WeeklyBossMaterialInterchange; LocalSetting.Set(SettingKeys.CultivationStatisticsMergeUpgradeMaterials, merge); LocalSetting.Set(SettingKeys.CultivationStatisticsTalentSynthCritTenPercent, talentCrit); + LocalSetting.Set(SettingKeys.CultivationStatisticsWeeklyBossMaterialInterchange, weeklyBoss); CancellationToken token = exclusiveTokenProvider.GetNewToken(); StatisticsCultivateItemCollection statistics; @@ -374,7 +379,7 @@ internal sealed partial class CultivationViewModel : Abstraction.ViewModel try { statistics = await cultivationService - .GetStatisticsCultivateItemCollectionAsync(Projects.CurrentItem, metadataContext, new CultivationStatisticsMergeOptions(merge, talentCrit), token) + .GetStatisticsCultivateItemCollectionAsync(Projects.CurrentItem, metadataContext, new CultivationStatisticsMergeOptions(merge, talentCrit, weeklyBoss), token) .ConfigureAwait(false); resinStatistics = await cultivationService.GetResinStatisticsAsync(statistics, token).ConfigureAwait(false); } diff --git a/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/StatisticsCultivateItem.cs b/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/StatisticsCultivateItem.cs index b44fd2a..2fe0e28 100644 --- a/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/StatisticsCultivateItem.cs +++ b/src/Snap.Hutao/Snap.Hutao/ViewModel/Cultivation/StatisticsCultivateItem.cs @@ -35,26 +35,33 @@ internal sealed class StatisticsCultivateItem /// public uint? MergeAdjustedCurrent { get; set; } - public uint DisplayCurrent { get => MergeAdjustedCurrent ?? Current; } + /// + /// 周本材料异梦转化池内调配后的展示用持有量;未启用时为 。在 之后应用。 + /// + public uint? WeeklyBossInterchangeAdjustedCurrent { get; set; } + + public uint DisplayCurrent { get => WeeklyBossInterchangeAdjustedCurrent ?? MergeAdjustedCurrent ?? Current; } public bool IsFinished { get => DisplayCurrent >= Count; } public string FormattedCount { get => $"{DisplayCurrent}/{Count}"; } + private bool HasStatisticsAdjustedDisplay { get => MergeAdjustedCurrent.HasValue || WeeklyBossInterchangeAdjustedCurrent.HasValue; } + /// 未启用合并展示链时,使用紧凑 - public bool ShowNonMergeCompactCount { get => !MergeAdjustedCurrent.HasValue; } + public bool ShowNonMergeCompactCount { get => !HasStatisticsAdjustedDisplay; } /// 已合并但合成前后有效持有量与背包数一致,不显示括号,仅「合并后 / 需求」加空格。 - public bool ShowMergeSpacedWithoutParen { get => MergeAdjustedCurrent.HasValue && DisplayCurrent == Current; } + public bool ShowMergeSpacedWithoutParen { get => HasStatisticsAdjustedDisplay && DisplayCurrent == Current; } /// 合并后有效持有与背包原数不同,显示「合并后 (背包原数)」。 - public bool ShowMergeInventoryParen { get => MergeAdjustedCurrent.HasValue && DisplayCurrent != Current; } + public bool ShowMergeInventoryParen { get => HasStatisticsAdjustedDisplay && DisplayCurrent != Current; } /// 首位合并显示量 > 背包原数时着红色(相对原库存变多)。 - public bool MergeDisplayLeadUseRed { get => MergeAdjustedCurrent.HasValue && DisplayCurrent > Current; } + public bool MergeDisplayLeadUseRed { get => HasStatisticsAdjustedDisplay && DisplayCurrent > Current; } /// 首位合并显示量 < 背包原数时着绿色(相对原库存变少,如低档被向上消耗)。 - public bool MergeDisplayLeadUseGreen { get => MergeAdjustedCurrent.HasValue && DisplayCurrent < Current; } + public bool MergeDisplayLeadUseGreen { get => HasStatisticsAdjustedDisplay && DisplayCurrent < Current; } /// 背包原数,紧接在合并后数字后,如 (44) public string RawInventoryParenthetical { get => $"({Current})"; }