mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
batch add for avatarinfo cultivation
This commit is contained in:
@@ -63,4 +63,17 @@ internal static class SettingKeys
|
||||
/// 覆盖管理员权限执行命令
|
||||
/// </summary>
|
||||
public const string OverrideElevationRequirement = "OverrideElevationRequirement";
|
||||
|
||||
public const string CultivationAvatarLevelCurrent = "CultivationAvatarLevelCurrent";
|
||||
public const string CultivationAvatarLevelTarget = "CultivationAvatarLevelTarget";
|
||||
public const string CultivationAvatarSkillACurrent = "CultivationAvatarSkillACurrent";
|
||||
public const string CultivationAvatarSkillATarget = "CultivationAvatarSkillATarget";
|
||||
public const string CultivationAvatarSkillECurrent = "CultivationAvatarSkillECurrent";
|
||||
public const string CultivationAvatarSkillETarget = "CultivationAvatarSkillETarget";
|
||||
public const string CultivationAvatarSkillQCurrent = "CultivationAvatarSkillQCurrent";
|
||||
public const string CultivationAvatarSkillQTarget = "CultivationAvatarSkillQTarget";
|
||||
public const string CultivationWeapon90LevelCurrent = "CultivationWeapon90LevelCurrent";
|
||||
public const string CultivationWeapon90LevelTarget = "CultivationWeapon90LevelTarget";
|
||||
public const string CultivationWeapon70LevelCurrent = "CultivationWeapon70LevelCurrent";
|
||||
public const string CultivationWeapon70LevelTarget = "CultivationWeapon70LevelTarget";
|
||||
}
|
||||
@@ -103,7 +103,7 @@ internal static partial class EnumerableExtension
|
||||
Span<TSource> span = CollectionsMarshal.AsSpan(list);
|
||||
List<TResult> results = new(span.Length);
|
||||
|
||||
foreach (TSource item in span)
|
||||
foreach (ref readonly TSource item in span)
|
||||
{
|
||||
results.Add(selector(item));
|
||||
}
|
||||
@@ -111,6 +111,21 @@ internal static partial class EnumerableExtension
|
||||
return results;
|
||||
}
|
||||
|
||||
[Pure]
|
||||
public static List<TResult> SelectList<TSource, TResult>(this List<TSource> list, Func<TSource, int, TResult> selector)
|
||||
{
|
||||
Span<TSource> span = CollectionsMarshal.AsSpan(list);
|
||||
List<TResult> results = new(span.Length);
|
||||
|
||||
int index = -1;
|
||||
foreach (ref readonly TSource item in span)
|
||||
{
|
||||
results.Add(selector(item, ++index));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public static async ValueTask<List<TResult>> SelectListAsync<TSource, TResult>(this List<TSource> list, Func<TSource, ValueTask<TResult>> selector)
|
||||
{
|
||||
List<TResult> results = new(list.Count);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
@@ -21,9 +22,6 @@ internal sealed class CalculableAvatar
|
||||
IMappingFrom<CalculableAvatar, Avatar>,
|
||||
IMappingFrom<CalculableAvatar, AvatarView>
|
||||
{
|
||||
private uint levelCurrent;
|
||||
private uint levelTarget;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的可计算角色
|
||||
/// </summary>
|
||||
@@ -32,14 +30,11 @@ internal sealed class CalculableAvatar
|
||||
{
|
||||
AvatarId = avatar.Id;
|
||||
LevelMin = 1;
|
||||
LevelMax = 90;
|
||||
Skills = avatar.SkillDepot.CompositeSkillsNoInherents().SelectList(p => p.ToCalculable());
|
||||
LevelMax = avatar.MaxLevel;
|
||||
Skills = avatar.SkillDepot.CompositeSkillsNoInherents().SelectList((p, i) => p.ToCalculable((SkillType)i));
|
||||
Name = avatar.Name;
|
||||
Icon = AvatarIconConverter.IconNameToUri(avatar.Icon);
|
||||
Quality = avatar.Quality;
|
||||
|
||||
LevelCurrent = LevelMin;
|
||||
LevelTarget = LevelMax;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -50,14 +45,11 @@ internal sealed class CalculableAvatar
|
||||
{
|
||||
AvatarId = avatar.Id;
|
||||
LevelMin = avatar.LevelNumber;
|
||||
LevelMax = 90; // hard coded 90
|
||||
Skills = avatar.Skills.SelectList(s => s.ToCalculable());
|
||||
LevelMax = Avatar.GetMaxLevel();
|
||||
Skills = avatar.Skills.SelectList((s, i) => s.ToCalculable((SkillType)i));
|
||||
Name = avatar.Name;
|
||||
Icon = avatar.Icon;
|
||||
Quality = avatar.Quality;
|
||||
|
||||
LevelCurrent = LevelMin;
|
||||
LevelTarget = LevelMax;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -82,10 +74,18 @@ internal sealed class CalculableAvatar
|
||||
public QualityType Quality { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
||||
public uint LevelCurrent
|
||||
{
|
||||
get => LocalSetting.Get(SettingKeys.CultivationAvatarLevelCurrent, LevelMin);
|
||||
set => SetProperty(LevelCurrent, value, v => LocalSetting.Set(SettingKeys.CultivationAvatarLevelCurrent, v));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||
public uint LevelTarget
|
||||
{
|
||||
get => LocalSetting.Get(SettingKeys.CultivationAvatarLevelTarget, LevelMax);
|
||||
set => SetProperty(LevelTarget, value, v => LocalSetting.Set(SettingKeys.CultivationAvatarLevelTarget, v));
|
||||
}
|
||||
|
||||
public static CalculableAvatar From(Avatar source)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata.Avatar;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
@@ -18,44 +19,33 @@ namespace Snap.Hutao.Model.Calculable;
|
||||
internal sealed class CalculableSkill
|
||||
: ObservableObject,
|
||||
ICalculableSkill,
|
||||
IMappingFrom<CalculableSkill, ProudableSkill>,
|
||||
IMappingFrom<CalculableSkill, SkillView>
|
||||
IMappingFrom<CalculableSkill, ProudableSkill, SkillType>,
|
||||
IMappingFrom<CalculableSkill, SkillView, SkillType>
|
||||
{
|
||||
private uint levelCurrent;
|
||||
private uint levelTarget;
|
||||
private readonly SkillType type;
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的可计算的技能
|
||||
/// </summary>
|
||||
/// <param name="skill">技能</param>
|
||||
private CalculableSkill(ProudableSkill skill)
|
||||
private CalculableSkill(ProudableSkill skill, SkillType type)
|
||||
{
|
||||
this.type = type;
|
||||
|
||||
GroupId = skill.GroupId;
|
||||
LevelMin = 1;
|
||||
LevelMax = 10; // hard coded 10 here
|
||||
LevelMax = ProudableSkill.GetMaxLevel();
|
||||
Name = skill.Name;
|
||||
Icon = SkillIconConverter.IconNameToUri(skill.Icon);
|
||||
Quality = QualityType.QUALITY_NONE;
|
||||
|
||||
LevelCurrent = LevelMin;
|
||||
LevelTarget = LevelMax;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 构造一个新的可计算的技能
|
||||
/// </summary>
|
||||
/// <param name="skill">技能</param>
|
||||
private CalculableSkill(SkillView skill)
|
||||
private CalculableSkill(SkillView skill, SkillType type)
|
||||
{
|
||||
this.type = type;
|
||||
|
||||
GroupId = skill.GroupId;
|
||||
LevelMin = skill.LevelNumber;
|
||||
LevelMax = 10; // hard coded 10 here
|
||||
LevelMax = ProudableSkill.GetMaxLevel();
|
||||
Name = skill.Name;
|
||||
Icon = skill.Icon;
|
||||
Quality = QualityType.QUALITY_NONE;
|
||||
|
||||
LevelCurrent = LevelMin;
|
||||
LevelTarget = LevelMax;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@@ -77,18 +67,48 @@ internal sealed class CalculableSkill
|
||||
public QualityType Quality { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
||||
public uint LevelCurrent
|
||||
{
|
||||
get => LocalSetting.Get(SettingKeyCurrentFromSkillType(type), LevelMin);
|
||||
set => SetProperty(LevelCurrent, value, v => LocalSetting.Set(SettingKeyCurrentFromSkillType(type), v));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||
|
||||
public static CalculableSkill From(ProudableSkill source)
|
||||
public uint LevelTarget
|
||||
{
|
||||
return new(source);
|
||||
get => LocalSetting.Get(SettingKeyTargetFromSkillType(type), LevelMax);
|
||||
set => SetProperty(LevelTarget, value, v => LocalSetting.Set(SettingKeyTargetFromSkillType(type), v));
|
||||
}
|
||||
|
||||
public static CalculableSkill From(SkillView source)
|
||||
public static CalculableSkill From(ProudableSkill source, SkillType type)
|
||||
{
|
||||
return new(source);
|
||||
return new(source, type);
|
||||
}
|
||||
|
||||
public static CalculableSkill From(SkillView source, SkillType type)
|
||||
{
|
||||
return new(source, type);
|
||||
}
|
||||
|
||||
public static string SettingKeyCurrentFromSkillType(SkillType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
SkillType.A => SettingKeys.CultivationAvatarSkillACurrent,
|
||||
SkillType.E => SettingKeys.CultivationAvatarSkillECurrent,
|
||||
SkillType.Q => SettingKeys.CultivationAvatarSkillQCurrent,
|
||||
_ => throw Must.NeverHappen(),
|
||||
};
|
||||
}
|
||||
|
||||
public static string SettingKeyTargetFromSkillType(SkillType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
SkillType.A => SettingKeys.CultivationAvatarSkillATarget,
|
||||
SkillType.E => SettingKeys.CultivationAvatarSkillETarget,
|
||||
SkillType.Q => SettingKeys.CultivationAvatarSkillQTarget,
|
||||
_ => throw Must.NeverHappen(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Snap.Hutao.Core.Abstraction;
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Model.Intrinsic;
|
||||
using Snap.Hutao.Model.Metadata.Converter;
|
||||
using Snap.Hutao.Model.Metadata.Weapon;
|
||||
@@ -77,10 +78,18 @@ internal sealed class CalculableWeapon
|
||||
public QualityType Quality { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint LevelCurrent { get => levelCurrent; set => SetProperty(ref levelCurrent, value); }
|
||||
public uint LevelCurrent
|
||||
{
|
||||
get => LocalSetting.Get(SettingKeyCurrentFromQualityType(Quality), LevelMin);
|
||||
set => SetProperty(LevelCurrent, value, v => LocalSetting.Set(SettingKeyCurrentFromQualityType(Quality), v));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public uint LevelTarget { get => levelTarget; set => SetProperty(ref levelTarget, value); }
|
||||
public uint LevelTarget
|
||||
{
|
||||
get => LocalSetting.Get(SettingKeyTargetFromQualityType(Quality), LevelMax);
|
||||
set => SetProperty(LevelTarget, value, v => LocalSetting.Set(SettingKeyTargetFromQualityType(Quality), v));
|
||||
}
|
||||
|
||||
public static CalculableWeapon From(Weapon source)
|
||||
{
|
||||
@@ -91,4 +100,18 @@ internal sealed class CalculableWeapon
|
||||
{
|
||||
return new(source);
|
||||
}
|
||||
|
||||
public static string SettingKeyCurrentFromQualityType(QualityType quality)
|
||||
{
|
||||
return quality >= QualityType.QUALITY_BLUE
|
||||
? SettingKeys.CultivationWeapon90LevelCurrent
|
||||
: SettingKeys.CultivationWeapon70LevelCurrent;
|
||||
}
|
||||
|
||||
public static string SettingKeyTargetFromQualityType(QualityType quality)
|
||||
{
|
||||
return quality >= QualityType.QUALITY_BLUE
|
||||
? SettingKeys.CultivationWeapon90LevelTarget
|
||||
: SettingKeys.CultivationWeapon70LevelTarget;
|
||||
}
|
||||
}
|
||||
@@ -6,14 +6,25 @@ namespace Snap.Hutao.Model.Calculable;
|
||||
/// <summary>
|
||||
/// 可计算物品的源
|
||||
/// </summary>
|
||||
/// <typeparam name="T">可计算类型</typeparam>
|
||||
/// <typeparam name="TResult">可计算类型</typeparam>
|
||||
[HighQuality]
|
||||
internal interface ICalculableSource<T>
|
||||
where T : ICalculable
|
||||
internal interface ICalculableSource<TResult>
|
||||
where TResult : ICalculable
|
||||
{
|
||||
/// <summary>
|
||||
/// 转换到可计算的对象
|
||||
/// </summary>
|
||||
/// <returns>可计算物品</returns>
|
||||
public T ToCalculable();
|
||||
public TResult ToCalculable();
|
||||
}
|
||||
|
||||
internal interface ITypedCalculableSource<TResult, T>
|
||||
where TResult : ICalculable
|
||||
{
|
||||
/// <summary>
|
||||
/// 转换到可计算的对象
|
||||
/// </summary>
|
||||
/// <param name="param">索引</param>
|
||||
/// <returns>可计算物品</returns>
|
||||
public TResult ToCalculable(T param);
|
||||
}
|
||||
11
src/Snap.Hutao/Snap.Hutao/Model/Calculable/SkillType.cs
Normal file
11
src/Snap.Hutao/Snap.Hutao/Model/Calculable/SkillType.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.Model.Calculable;
|
||||
|
||||
internal enum SkillType
|
||||
{
|
||||
A,
|
||||
E,
|
||||
Q,
|
||||
}
|
||||
@@ -39,7 +39,12 @@ internal partial class Avatar : IStatisticsItemSource, ISummaryItemSource, IItem
|
||||
/// 最大等级
|
||||
/// </summary>
|
||||
[SuppressMessage("", "CA1822")]
|
||||
public uint MaxLevel { get => 90U; }
|
||||
public uint MaxLevel { get => GetMaxLevel(); }
|
||||
|
||||
public static uint GetMaxLevel()
|
||||
{
|
||||
return 90U;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICalculableAvatar ToCalculable()
|
||||
|
||||
@@ -8,11 +8,16 @@ namespace Snap.Hutao.Model.Metadata.Avatar;
|
||||
/// <summary>
|
||||
/// 技能信息的接口实现
|
||||
/// </summary>
|
||||
internal sealed partial class ProudableSkill : ICalculableSource<ICalculableSkill>
|
||||
internal sealed partial class ProudableSkill : ITypedCalculableSource<ICalculableSkill, SkillType>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public ICalculableSkill ToCalculable()
|
||||
public static uint GetMaxLevel()
|
||||
{
|
||||
return CalculableSkill.From(this);
|
||||
return 10U;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICalculableSkill ToCalculable(SkillType type)
|
||||
{
|
||||
return CalculableSkill.From(this, type);
|
||||
}
|
||||
}
|
||||
@@ -2256,6 +2256,51 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 角色目标等级 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewDialogCultivateBatchAvatarLevelTarget {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewDialogCultivateBatchAvatarLevelTarget", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 普通攻击目标等级 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewDialogCultivateBatchSkillATarget {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewDialogCultivateBatchSkillATarget", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 元素战技目标等级 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewDialogCultivateBatchSkillETarget {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewDialogCultivateBatchSkillETarget", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 元素爆发目标等级 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewDialogCultivateBatchSkillQTarget {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewDialogCultivateBatchSkillQTarget", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 武器目标等级 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewDialogCultivateBatchWeaponLevelTarget {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewDialogCultivateBatchWeaponLevelTarget", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 绑定当前用户与角色 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2284,7 +2329,16 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 添加到当前养成计划 的本地化字符串。
|
||||
/// 查找类似 批量添加或更新到当前养成计划 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewDialogCultivatePromotionDeltaBatchTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewDialogCultivatePromotionDeltaBatchTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 添加或更新到当前养成计划 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewDialogCultivatePromotionDeltaTitle {
|
||||
get {
|
||||
@@ -2895,6 +2949,15 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 获取培养材料中,请稍候... 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewModelAvatarPropertyBatchCultivateProgressTitle {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewModelAvatarPropertyBatchCultivateProgressTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 当前角色无法计算,请同步信息后再试 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -2967,6 +3030,24 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 操作完成:添加/更新:{0} 个,跳过 {1} 个 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewModelCultivationBatchAddCompletedFormat {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewModelCultivationBatchAddCompletedFormat", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 操作未全部完成:添加/更新:{0} 个,跳过 {1} 个 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewModelCultivationBatchAddIncompletedFormat {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewModelCultivationBatchAddIncompletedFormat", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 已成功添加至当前养成计划 的本地化字符串。
|
||||
/// </summary>
|
||||
@@ -3642,6 +3723,24 @@ namespace Snap.Hutao.Resource.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 所有角色与武器 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageAvatarPropertyCalculateAll {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageAvatarPropertyCalculateAll", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 当前角色与武器 的本地化字符串。
|
||||
/// </summary>
|
||||
internal static string ViewPageAvatarPropertyCalculateCurrent {
|
||||
get {
|
||||
return ResourceManager.GetString("ViewPageAvatarPropertyCalculateCurrent", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找类似 双暴评分 的本地化字符串。
|
||||
/// </summary>
|
||||
|
||||
@@ -905,6 +905,21 @@
|
||||
<data name="ViewDialogAchievementArchiveImportTitle" xml:space="preserve">
|
||||
<value>为当前存档导入成就</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivateBatchAvatarLevelTarget" xml:space="preserve">
|
||||
<value>角色目标等级</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivateBatchSkillATarget" xml:space="preserve">
|
||||
<value>普通攻击目标等级</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivateBatchSkillETarget" xml:space="preserve">
|
||||
<value>元素战技目标等级</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivateBatchSkillQTarget" xml:space="preserve">
|
||||
<value>元素爆发目标等级</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivateBatchWeaponLevelTarget" xml:space="preserve">
|
||||
<value>武器目标等级</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivateProjectAttachUid" xml:space="preserve">
|
||||
<value>绑定当前用户与角色</value>
|
||||
</data>
|
||||
@@ -914,8 +929,11 @@
|
||||
<data name="ViewDialogCultivateProjectTitle" xml:space="preserve">
|
||||
<value>创建新的养成计划</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivatePromotionDeltaBatchTitle" xml:space="preserve">
|
||||
<value>批量添加或更新到当前养成计划</value>
|
||||
</data>
|
||||
<data name="ViewDialogCultivatePromotionDeltaTitle" xml:space="preserve">
|
||||
<value>添加到当前养成计划</value>
|
||||
<value>添加或更新到当前养成计划</value>
|
||||
</data>
|
||||
<data name="ViewDialogDailyNoteNotificationDailyTaskNotify" xml:space="preserve">
|
||||
<value>每日委托上线提醒</value>
|
||||
@@ -1118,6 +1136,9 @@
|
||||
<data name="ViewModelAchievementRemoveArchiveTitle" xml:space="preserve">
|
||||
<value>确定要删除存档 {0} 吗?</value>
|
||||
</data>
|
||||
<data name="ViewModelAvatarPropertyBatchCultivateProgressTitle" xml:space="preserve">
|
||||
<value>获取培养材料中,请稍候...</value>
|
||||
</data>
|
||||
<data name="ViewModelAvatarPropertyCalculateWeaponNull" xml:space="preserve">
|
||||
<value>当前角色无法计算,请同步信息后再试</value>
|
||||
</data>
|
||||
@@ -1142,6 +1163,12 @@
|
||||
<data name="ViewModelCultivationAddWarning" xml:space="preserve">
|
||||
<value>养成计划添加失败</value>
|
||||
</data>
|
||||
<data name="ViewModelCultivationBatchAddCompletedFormat" xml:space="preserve">
|
||||
<value>操作完成:添加/更新:{0} 个,跳过 {1} 个</value>
|
||||
</data>
|
||||
<data name="ViewModelCultivationBatchAddIncompletedFormat" xml:space="preserve">
|
||||
<value>操作未全部完成:添加/更新:{0} 个,跳过 {1} 个</value>
|
||||
</data>
|
||||
<data name="ViewModelCultivationEntryAddSuccess" xml:space="preserve">
|
||||
<value>已成功添加至当前养成计划</value>
|
||||
</data>
|
||||
@@ -1367,6 +1394,12 @@
|
||||
<data name="ViewPageAvatarPropertyArtifactScore" xml:space="preserve">
|
||||
<value>圣遗物评分</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyCalculateAll" xml:space="preserve">
|
||||
<value>所有角色与武器</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyCalculateCurrent" xml:space="preserve">
|
||||
<value>当前角色与武器</value>
|
||||
</data>
|
||||
<data name="ViewPageAvatarPropertyCritScore" xml:space="preserve">
|
||||
<value>双暴评分</value>
|
||||
</data>
|
||||
|
||||
@@ -106,7 +106,7 @@ internal sealed partial class CultivationDbService : ICultivationDbService
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask InsertCultivateEntryAsync(CultivateEntry entry)
|
||||
public async ValueTask AddCultivateEntryAsync(CultivateEntry entry)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
@@ -126,7 +126,7 @@ internal sealed partial class CultivationDbService : ICultivationDbService
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask InsertCultivateItemRangeAsync(IEnumerable<CultivateItem> toAdd)
|
||||
public async ValueTask AddCultivateItemRangeAsync(IEnumerable<CultivateItem> toAdd)
|
||||
{
|
||||
using (IServiceScope scope = serviceProvider.CreateScope())
|
||||
{
|
||||
|
||||
@@ -177,14 +177,14 @@ internal sealed partial class CultivationService : ICultivationService
|
||||
if (entry is null)
|
||||
{
|
||||
entry = CultivateEntry.From(Current.InnerId, type, itemId);
|
||||
await cultivationDbService.InsertCultivateEntryAsync(entry).ConfigureAwait(false);
|
||||
await cultivationDbService.AddCultivateEntryAsync(entry).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Guid entryId = entry.InnerId;
|
||||
await cultivationDbService.DeleteCultivateItemRangeByEntryIdAsync(entryId).ConfigureAwait(false);
|
||||
|
||||
IEnumerable<CultivateItem> toAdd = items.Select(item => CultivateItem.From(entryId, item));
|
||||
await cultivationDbService.InsertCultivateItemRangeAsync(toAdd).ConfigureAwait(false);
|
||||
await cultivationDbService.AddCultivateItemRangeAsync(toAdd).ConfigureAwait(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,9 +28,9 @@ internal interface ICultivationDbService
|
||||
|
||||
ValueTask<List<InventoryItem>> GetInventoryItemListByProjectIdAsync(Guid projectId);
|
||||
|
||||
ValueTask InsertCultivateEntryAsync(CultivateEntry entry);
|
||||
ValueTask AddCultivateEntryAsync(CultivateEntry entry);
|
||||
|
||||
ValueTask InsertCultivateItemRangeAsync(IEnumerable<CultivateItem> toAdd);
|
||||
ValueTask AddCultivateItemRangeAsync(IEnumerable<CultivateItem> toAdd);
|
||||
|
||||
void UpdateCultivateItem(CultivateItem item);
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@
|
||||
<None Remove="View\Dialog\AchievementArchiveCreateDialog.xaml" />
|
||||
<None Remove="View\Dialog\AchievementImportDialog.xaml" />
|
||||
<None Remove="View\Dialog\CultivateProjectDialog.xaml" />
|
||||
<None Remove="View\Dialog\CultivatePromotionDeltaBatchDialog.xaml" />
|
||||
<None Remove="View\Dialog\CultivatePromotionDeltaDialog.xaml" />
|
||||
<None Remove="View\Dialog\DailyNoteNotificationDialog.xaml" />
|
||||
<None Remove="View\Dialog\GachaLogImportDialog.xaml" />
|
||||
@@ -299,6 +300,12 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="View\Dialog\CultivatePromotionDeltaBatchDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="View\Control\StatisticsSegmented.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</Grid>
|
||||
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<StackPanel Margin="16,0,16,16">
|
||||
<StackPanel Margin="16,0,12,16">
|
||||
<TextBlock
|
||||
Margin="0,16,0,8"
|
||||
Style="{StaticResource BaseTextBlockStyle}"
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<ContentDialog
|
||||
x:Class="Snap.Hutao.View.Dialog.CultivatePromotionDeltaBatchDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:cwc="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shvd="using:Snap.Hutao.View.Dialog"
|
||||
Title="{shcm:ResourceString Name=ViewDialogCultivatePromotionDeltaBatchTitle}"
|
||||
d:DataContext="{d:DesignInstance shvd:CultivatePromotionDeltaDialog}"
|
||||
CloseButtonText="{shcm:ResourceString Name=ContentDialogCancelCloseButtonText}"
|
||||
DefaultButton="Primary"
|
||||
PrimaryButtonText="{shcm:ResourceString Name=ContentDialogConfirmPrimaryButtonText}"
|
||||
Style="{StaticResource DefaultContentDialogStyle}"
|
||||
mc:Ignorable="d">
|
||||
<ContentDialog.Resources>
|
||||
<x:Double x:Key="NumberBoxMinWidth">180</x:Double>
|
||||
|
||||
<x:Double x:Key="SettingsCardSpacing">3</x:Double>
|
||||
<x:Double x:Key="SettingsCardMinHeight">0</x:Double>
|
||||
<x:Double x:Key="SettingsCardWrapThreshold">0</x:Double>
|
||||
<x:Double x:Key="SettingsCardWrapNoIconThreshold">0</x:Double>
|
||||
</ContentDialog.Resources>
|
||||
<StackPanel Spacing="{StaticResource SettingsCardSpacing}">
|
||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewDialogCultivateBatchAvatarLevelTarget}">
|
||||
<NumberBox
|
||||
Grid.Column="2"
|
||||
MinWidth="{StaticResource NumberBoxMinWidth}"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="90"
|
||||
Minimum="1"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind PromotionDelta.AvatarLevelTarget, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewDialogCultivateBatchSkillATarget}">
|
||||
<NumberBox
|
||||
Grid.Column="2"
|
||||
MinWidth="{StaticResource NumberBoxMinWidth}"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="10"
|
||||
Minimum="1"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind PromotionDelta.SkillList[0].LevelTarget, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewDialogCultivateBatchSkillETarget}">
|
||||
<NumberBox
|
||||
Grid.Column="2"
|
||||
MinWidth="{StaticResource NumberBoxMinWidth}"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="10"
|
||||
Minimum="1"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind PromotionDelta.SkillList[1].LevelTarget, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewDialogCultivateBatchSkillQTarget}">
|
||||
<NumberBox
|
||||
Grid.Column="2"
|
||||
MinWidth="{StaticResource NumberBoxMinWidth}"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="10"
|
||||
Minimum="1"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind PromotionDelta.SkillList[2].LevelTarget, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
<cwc:SettingsCard Header="{shcm:ResourceString Name=ViewDialogCultivateBatchWeaponLevelTarget}">
|
||||
<NumberBox
|
||||
Grid.Column="2"
|
||||
MinWidth="{StaticResource NumberBoxMinWidth}"
|
||||
VerticalAlignment="Center"
|
||||
Maximum="90"
|
||||
Minimum="1"
|
||||
SpinButtonPlacementMode="Inline"
|
||||
Value="{x:Bind PromotionDelta.Weapon.LevelTarget, Mode=TwoWay}"/>
|
||||
</cwc:SettingsCard>
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
|
||||
namespace Snap.Hutao.View.Dialog;
|
||||
|
||||
[DependencyProperty("PromotionDelta", typeof(AvatarPromotionDelta))]
|
||||
internal sealed partial class CultivatePromotionDeltaBatchDialog : ContentDialog
|
||||
{
|
||||
private readonly ITaskContext taskContext;
|
||||
|
||||
public CultivatePromotionDeltaBatchDialog(IServiceProvider serviceProvider)
|
||||
{
|
||||
InitializeComponent();
|
||||
XamlRoot = serviceProvider.GetRequiredService<MainWindow>().Content.XamlRoot;
|
||||
|
||||
taskContext = serviceProvider.GetRequiredService<ITaskContext>();
|
||||
|
||||
PromotionDelta = AvatarPromotionDelta.CreateForBaseline();
|
||||
}
|
||||
|
||||
public async ValueTask<ValueResult<bool, AvatarPromotionDelta>> GetPromotionDeltaBaselineAsync()
|
||||
{
|
||||
await taskContext.SwitchToMainThreadAsync();
|
||||
ContentDialogResult result = await ShowAsync();
|
||||
|
||||
return new(result == ContentDialogResult.Primary, PromotionDelta);
|
||||
}
|
||||
}
|
||||
@@ -7,9 +7,7 @@
|
||||
xmlns:shci="using:Snap.Hutao.Control.Image"
|
||||
xmlns:shcm="using:Snap.Hutao.Control.Markup"
|
||||
xmlns:shvc="using:Snap.Hutao.View.Control"
|
||||
xmlns:shvd="using:Snap.Hutao.View.Dialog"
|
||||
Title="{shcm:ResourceString Name=ViewDialogCultivatePromotionDeltaTitle}"
|
||||
d:DataContext="{d:DesignInstance shvd:CultivatePromotionDeltaDialog}"
|
||||
CloseButtonText="{shcm:ResourceString Name=ContentDialogCancelCloseButtonText}"
|
||||
DefaultButton="Primary"
|
||||
PrimaryButtonText="{shcm:ResourceString Name=ContentDialogConfirmPrimaryButtonText}"
|
||||
@@ -27,9 +25,9 @@
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Margin="0,8,0,0"
|
||||
Visibility="{Binding Avatar, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
Visibility="{x:Bind Avatar, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<Grid Margin="8" DataContext="{Binding Avatar}">
|
||||
<Grid Margin="8" DataContext="{x:Bind Avatar}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="160"/>
|
||||
@@ -73,7 +71,7 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<ItemsControl ItemsSource="{Binding Avatar.Skills}">
|
||||
<ItemsControl ItemsSource="{x:Bind Avatar.Skills}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="0,2,0,0" Style="{StaticResource BorderCardStyle}">
|
||||
@@ -128,7 +126,7 @@
|
||||
Margin="0,8,0,0"
|
||||
Visibility="{Binding Weapon, Converter={StaticResource EmptyObjectToVisibilityConverter}}">
|
||||
<Border Style="{StaticResource BorderCardStyle}">
|
||||
<Grid Margin="8" DataContext="{Binding Weapon}">
|
||||
<Grid Margin="8" DataContext="{x:Bind Weapon}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="auto"/>
|
||||
<ColumnDefinition Width="160"/>
|
||||
|
||||
@@ -33,7 +33,6 @@ internal sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
||||
|
||||
Avatar = options.Avatar;
|
||||
Weapon = options.Weapon;
|
||||
DataContext = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,19 +52,19 @@ internal sealed partial class CultivatePromotionDeltaDialog : ContentDialog
|
||||
AvatarPromotionDelta delta = new()
|
||||
{
|
||||
AvatarId = Avatar?.AvatarId ?? 0,
|
||||
AvatarLevelCurrent = Avatar?.LevelCurrent ?? 0,
|
||||
AvatarLevelTarget = Avatar?.LevelTarget ?? 0,
|
||||
SkillList = Avatar?.Skills.SelectList(s => new PromotionDelta()
|
||||
AvatarLevelCurrent = Avatar is not null ? Math.Clamp(Avatar.LevelCurrent, Avatar.LevelMin, Avatar.LevelMax) : 0,
|
||||
AvatarLevelTarget = Avatar is not null ? Math.Clamp(Avatar.LevelTarget, Avatar.LevelMin, Avatar.LevelMax) : 0,
|
||||
SkillList = Avatar?.Skills.SelectList(skill => new PromotionDelta()
|
||||
{
|
||||
Id = s.GroupId,
|
||||
LevelCurrent = s.LevelCurrent,
|
||||
LevelTarget = s.LevelTarget,
|
||||
Id = skill.GroupId,
|
||||
LevelCurrent = Math.Clamp(skill.LevelCurrent, skill.LevelMin, skill.LevelMax),
|
||||
LevelTarget = Math.Clamp(skill.LevelTarget, skill.LevelMin, skill.LevelMax),
|
||||
}),
|
||||
Weapon = Weapon is null ? null : new PromotionDelta()
|
||||
{
|
||||
Id = Weapon.WeaponId,
|
||||
LevelCurrent = Weapon.LevelCurrent,
|
||||
LevelTarget = Weapon.LevelTarget,
|
||||
LevelCurrent = Math.Clamp(Weapon.LevelCurrent, Weapon.LevelMin, Weapon.LevelMax),
|
||||
LevelTarget = Math.Clamp(Weapon.LevelTarget, Weapon.LevelMin, Weapon.LevelMax),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -89,11 +89,17 @@
|
||||
CommandParameter="{Binding ElementName=ItemsPanelSelector, Path=Current, Converter={StaticResource PanelSelectorModeConverter}}"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Label="{shcm:ResourceString Name=ViewPageAvatarPropertyExportAsImage}"/>
|
||||
<AppBarButton
|
||||
Command="{Binding CultivateCommand}"
|
||||
CommandParameter="{Binding SelectedAvatar}"
|
||||
Icon="{shcm:FontIcon Glyph=}"
|
||||
Label="{shcm:ResourceString Name=ViewPageCultivateCalculate}"/>
|
||||
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="{shcm:ResourceString Name=ViewPageCultivateCalculate}">
|
||||
<AppBarButton.Flyout>
|
||||
<MenuFlyout>
|
||||
<MenuFlyoutItem
|
||||
Command="{Binding CultivateCommand}"
|
||||
CommandParameter="{Binding SelectedAvatar}"
|
||||
Text="{shcm:ResourceString Name=ViewPageAvatarPropertyCalculateCurrent}"/>
|
||||
<MenuFlyoutItem Command="{Binding BatchCultivateCommand}" Text="{shcm:ResourceString Name=ViewPageAvatarPropertyCalculateAll}"/>
|
||||
</MenuFlyout>
|
||||
</AppBarButton.Flyout>
|
||||
</AppBarButton>
|
||||
<AppBarSeparator/>
|
||||
<AppBarButton Icon="{shcm:FontIcon Glyph=}" Label="{shcm:ResourceString Name=ViewAvatarPropertySyncDataButtonLabel}">
|
||||
<AppBarButton.Flyout>
|
||||
|
||||
@@ -44,9 +44,9 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
private readonly IAvatarInfoService avatarInfoService;
|
||||
private readonly IClipboardInterop clipboardInterop;
|
||||
private readonly CalculatorClient calculatorClient;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
private readonly ITaskContext taskContext;
|
||||
private readonly IUserService userService;
|
||||
private readonly IInfoBarService infoBarService;
|
||||
|
||||
private Summary? summary;
|
||||
private AvatarView? selectedAvatar;
|
||||
@@ -161,66 +161,168 @@ internal sealed partial class AvatarPropertyViewModel : Abstraction.ViewModel, I
|
||||
[Command("CultivateCommand")]
|
||||
private async Task CultivateAsync(AvatarView? avatar)
|
||||
{
|
||||
if (avatar is not null)
|
||||
if (avatar is null)
|
||||
{
|
||||
if (userService.Current is not null)
|
||||
return;
|
||||
}
|
||||
|
||||
if (userService.Current is null)
|
||||
{
|
||||
infoBarService.Warning(SH.MustSelectUserAndUid);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (avatar.Weapon is null)
|
||||
{
|
||||
if (avatar.Weapon is null)
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelAvatarPropertyCalculateWeaponNull);
|
||||
return;
|
||||
}
|
||||
infoBarService.Warning(SH.ViewModelAvatarPropertyCalculateWeaponNull);
|
||||
return;
|
||||
}
|
||||
|
||||
// ContentDialog must be created by main thread.
|
||||
CalculableOptions options = new(avatar.ToCalculable(), avatar.Weapon.ToCalculable());
|
||||
CultivatePromotionDeltaDialog dialog = await contentDialogFactory.CreateInstanceAsync<CultivatePromotionDeltaDialog>(options).ConfigureAwait(false);
|
||||
(bool isOk, CalculatorAvatarPromotionDelta delta) = await dialog.GetPromotionDeltaAsync().ConfigureAwait(false);
|
||||
CalculableOptions options = new(avatar.ToCalculable(), avatar.Weapon.ToCalculable());
|
||||
CultivatePromotionDeltaDialog dialog = await contentDialogFactory.CreateInstanceAsync<CultivatePromotionDeltaDialog>(options).ConfigureAwait(false);
|
||||
(bool isOk, CalculatorAvatarPromotionDelta delta) = await dialog.GetPromotionDeltaAsync().ConfigureAwait(false);
|
||||
|
||||
if (!isOk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!isOk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Response<CalculatorConsumption> consumptionResponse = await calculatorClient
|
||||
.ComputeAsync(userService.Current.Entity, delta)
|
||||
Response<CalculatorConsumption> consumptionResponse = await calculatorClient
|
||||
.ComputeAsync(userService.Current.Entity, delta)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!consumptionResponse.IsOk())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CalculatorConsumption consumption = consumptionResponse.Data;
|
||||
|
||||
List<CalculatorItem> items = CalculatorItemHelper.Merge(consumption.AvatarConsume, consumption.AvatarSkillConsume);
|
||||
bool avatarSaved = await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.AvatarAndSkill, avatar.Id, items)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
// take a hot path if avatar is not saved.
|
||||
bool avatarAndWeaponSaved = avatarSaved && await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.Weapon, avatar.Weapon.Id, consumption.WeaponConsume.EmptyIfNull())
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!consumptionResponse.IsOk())
|
||||
if (avatarAndWeaponSaved)
|
||||
{
|
||||
return;
|
||||
infoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
||||
}
|
||||
|
||||
CalculatorConsumption consumption = consumptionResponse.Data;
|
||||
|
||||
List<CalculatorItem> items = CalculatorItemHelper.Merge(consumption.AvatarConsume, consumption.AvatarSkillConsume);
|
||||
bool avatarSaved = await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.AvatarAndSkill, avatar.Id, items)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
try
|
||||
else
|
||||
{
|
||||
// take a hot path if avatar is not saved.
|
||||
bool avatarAndWeaponSaved = avatarSaved && await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.Weapon, avatar.Weapon.Id, consumption.WeaponConsume.EmptyIfNull())
|
||||
.ConfigureAwait(false);
|
||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
}
|
||||
}
|
||||
catch (Core.ExceptionService.UserdataCorruptedException ex)
|
||||
{
|
||||
infoBarService.Error(ex, SH.ViewModelCultivationAddWarning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (avatarAndWeaponSaved)
|
||||
{
|
||||
infoBarService.Success(SH.ViewModelCultivationEntryAddSuccess);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelCultivationEntryAddWarning);
|
||||
}
|
||||
}
|
||||
catch (Core.ExceptionService.UserdataCorruptedException ex)
|
||||
{
|
||||
infoBarService.Error(ex, SH.ViewModelCultivationAddWarning);
|
||||
}
|
||||
[Command("BatchCultivateCommand")]
|
||||
private async Task BatchCultivateAsync()
|
||||
{
|
||||
if (summary is { Avatars: { } avatars })
|
||||
{
|
||||
if (userService.Current is null)
|
||||
{
|
||||
infoBarService.Warning(SH.MustSelectUserAndUid);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Warning(SH.MustSelectUserAndUid);
|
||||
CultivatePromotionDeltaBatchDialog dialog = await contentDialogFactory.CreateInstanceAsync<CultivatePromotionDeltaBatchDialog>().ConfigureAwait(false);
|
||||
(bool isOk, CalculatorAvatarPromotionDelta baseline) = await dialog.GetPromotionDeltaBaselineAsync().ConfigureAwait(false);
|
||||
|
||||
if (isOk)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(baseline.SkillList);
|
||||
ArgumentNullException.ThrowIfNull(baseline.Weapon);
|
||||
|
||||
ContentDialog progressDialog = await contentDialogFactory
|
||||
.CreateForIndeterminateProgressAsync(SH.ViewModelAvatarPropertyBatchCultivateProgressTitle)
|
||||
.ConfigureAwait(false);
|
||||
using (await progressDialog.BlockAsync(taskContext).ConfigureAwait(false))
|
||||
{
|
||||
BatchCultivateResult result = default;
|
||||
foreach (AvatarView avatar in avatars)
|
||||
{
|
||||
baseline.AvatarId = avatar.Id;
|
||||
baseline.AvatarLevelCurrent = Math.Min(avatar.LevelNumber, baseline.AvatarLevelTarget);
|
||||
baseline.SkillList[0].Id = avatar.Skills[0].GroupId;
|
||||
baseline.SkillList[0].LevelCurrent = Math.Min(avatar.Skills[0].LevelNumber, baseline.SkillList[0].LevelTarget);
|
||||
baseline.SkillList[1].Id = avatar.Skills[1].GroupId;
|
||||
baseline.SkillList[1].LevelCurrent = Math.Min(avatar.Skills[1].LevelNumber, baseline.SkillList[1].LevelTarget);
|
||||
baseline.SkillList[2].Id = avatar.Skills[2].GroupId;
|
||||
baseline.SkillList[2].LevelCurrent = Math.Min(avatar.Skills[2].LevelNumber, baseline.SkillList[2].LevelTarget);
|
||||
|
||||
if (avatar.Weapon is null)
|
||||
{
|
||||
result.SkippedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
baseline.Weapon.Id = avatar.Weapon.Id;
|
||||
baseline.Weapon.LevelCurrent = Math.Min(avatar.Weapon.LevelNumber, baseline.Weapon.LevelTarget);
|
||||
|
||||
Response<CalculatorConsumption> consumptionResponse = await calculatorClient
|
||||
.ComputeAsync(userService.Current.Entity, baseline)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!consumptionResponse.IsOk())
|
||||
{
|
||||
result.Interrupted = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
CalculatorConsumption consumption = consumptionResponse.Data;
|
||||
|
||||
List<CalculatorItem> items = CalculatorItemHelper.Merge(consumption.AvatarConsume, consumption.AvatarSkillConsume);
|
||||
bool avatarSaved = await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.AvatarAndSkill, avatar.Id, items)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
// take a hot path if avatar is not saved.
|
||||
bool avatarAndWeaponSaved = avatarSaved && await cultivationService
|
||||
.SaveConsumptionAsync(CultivateType.Weapon, avatar.Weapon.Id, consumption.WeaponConsume.EmptyIfNull())
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (avatarAndWeaponSaved)
|
||||
{
|
||||
result.SucceedCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Interrupted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Core.ExceptionService.UserdataCorruptedException ex)
|
||||
{
|
||||
infoBarService.Error(ex, SH.ViewModelCultivationAddWarning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Interrupted)
|
||||
{
|
||||
infoBarService.Warning(SH.ViewModelCultivationBatchAddIncompletedFormat.Format(result.SucceedCount, result.SkippedCount));
|
||||
}
|
||||
else
|
||||
{
|
||||
infoBarService.Success(SH.ViewModelCultivationBatchAddCompletedFormat.Format(result.SucceedCount, result.SkippedCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ internal sealed class AvatarView : INameIconSide, ICalculableSource<ICalculableA
|
||||
/// <summary>
|
||||
/// 武器
|
||||
/// </summary>
|
||||
public WeaponView? Weapon { get; set; } = default!;
|
||||
public WeaponView? Weapon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 圣遗物列表
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
namespace Snap.Hutao.ViewModel.AvatarProperty;
|
||||
|
||||
internal struct BatchCultivateResult
|
||||
{
|
||||
public int SucceedCount;
|
||||
public int SkippedCount;
|
||||
public bool Interrupted;
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace Snap.Hutao.ViewModel.AvatarProperty;
|
||||
/// 天赋
|
||||
/// </summary>
|
||||
[HighQuality]
|
||||
internal sealed class SkillView : NameIconDescription, ICalculableSource<ICalculableSkill>
|
||||
internal sealed class SkillView : NameIconDescription, ITypedCalculableSource<ICalculableSkill, SkillType>
|
||||
{
|
||||
/// <summary>
|
||||
/// 技能属性
|
||||
@@ -34,8 +34,8 @@ internal sealed class SkillView : NameIconDescription, ICalculableSource<ICalcul
|
||||
internal SkillGroupId GroupId { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICalculableSkill ToCalculable()
|
||||
public ICalculableSkill ToCalculable(SkillType type)
|
||||
{
|
||||
return CalculableSkill.From(this);
|
||||
return CalculableSkill.From(this, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) DGP Studio. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
using Snap.Hutao.Core.Setting;
|
||||
using Snap.Hutao.Model.Primitive;
|
||||
|
||||
namespace Snap.Hutao.Web.Hoyolab.Takumi.Event.Calculate;
|
||||
@@ -46,4 +47,19 @@ internal sealed class AvatarPromotionDelta
|
||||
/// </summary>
|
||||
[JsonPropertyName("weapon")]
|
||||
public PromotionDelta? Weapon { get; set; }
|
||||
|
||||
public static AvatarPromotionDelta CreateForBaseline()
|
||||
{
|
||||
return new()
|
||||
{
|
||||
AvatarLevelTarget = LocalSetting.Get(SettingKeys.CultivationAvatarLevelTarget, 90U),
|
||||
SkillList = new()
|
||||
{
|
||||
new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationAvatarSkillATarget, 10U), },
|
||||
new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationAvatarSkillETarget, 10U), },
|
||||
new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationAvatarSkillQTarget, 10U), },
|
||||
},
|
||||
Weapon = new() { LevelTarget = LocalSetting.Get(SettingKeys.CultivationWeapon90LevelTarget, 90U), },
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user