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})"; }