diff --git a/data/Achievement.json b/data/Achievement.json
index 0ff1779f15..f6c2442141 100644
--- a/data/Achievement.json
+++ b/data/Achievement.json
@@ -1,162 +1,206 @@
{
"FirstLaunch": {
"Id": "FirstLaunch",
- "CustomData": {}
- },
- "Irreplaceable": {
- "Id": "Irreplaceable",
- "CustomData": {}
- },
- "MosquitoLeg": {
- "Id": "MosquitoLeg",
- "CustomData": {}
- },
- "PioneerTest": {
- "Id": "PioneerTest",
- "CustomData": {}
- },
- "ProblemFeedback": {
- "Id": "ProblemFeedback",
- "CustomData": {}
- },
- "RecruitNoSixStar": {
- "Id": "RecruitNoSixStar",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"SanityExpire": {
"Id": "SanityExpire",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"SanitySaver1": {
"Id": "SanitySaver1",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"SanitySaver2": {
"Id": "SanitySaver2",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"SanitySaver3": {
"Id": "SanitySaver3",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"SanitySpender1": {
"Id": "SanitySpender1",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"SanitySpender2": {
"Id": "SanitySpender2",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"SanitySpender3": {
"Id": "SanitySpender3",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "MosquitoLeg": {
+ "Id": "MosquitoLeg",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "PioneerTest": {
+ "Id": "PioneerTest",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"ScheduleMaster1": {
"Id": "ScheduleMaster1",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"ScheduleMaster2": {
"Id": "ScheduleMaster2",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
- "SnapshotChallenge10": {
- "Id": "SnapshotChallenge10",
- "CustomData": {}
- },
- "SnapshotChallenge100": {
- "Id": "SnapshotChallenge100",
- "CustomData": {}
- },
- "SnapshotChallenge400": {
- "Id": "SnapshotChallenge400",
- "CustomData": {}
- },
- "SnapshotChallenge800": {
- "Id": "SnapshotChallenge800",
- "CustomData": {}
- },
- "SnapshotChallenge999": {
- "Id": "SnapshotChallenge999",
- "CustomData": {}
+ "Irreplaceable": {
+ "Id": "Irreplaceable",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"UseCopilot1": {
"Id": "UseCopilot1",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"UseCopilot2": {
"Id": "UseCopilot2",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"UseCopilot3": {
"Id": "UseCopilot3",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
- "CongratulationError": {
- "Id": "CongratulationError",
- "CustomData": {}
+ "RecruitNoSixStar": {
+ "Id": "RecruitNoSixStar",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
- "CustomizationMaster": {
- "Id": "CustomizationMaster",
- "CustomData": {}
+ "SnapshotChallenge10": {
+ "Id": "SnapshotChallenge10",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
- "MapOutdated": {
- "Id": "MapOutdated",
- "CustomData": {}
+ "SnapshotChallenge100": {
+ "Id": "SnapshotChallenge100",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
- "Martian": {
- "Id": "Martian",
- "CustomData": {}
+ "SnapshotChallenge400": {
+ "Id": "SnapshotChallenge400",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
- "MirrorChyanCdkError": {
- "Id": "MirrorChyanCdkError",
- "CustomData": {}
- },
- "MirrorChyanFirstUse": {
- "Id": "MirrorChyanFirstUse",
- "CustomData": {}
+ "ProblemFeedback": {
+ "Id": "ProblemFeedback",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"OverLimitAgent": {
"Id": "OverLimitAgent",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
- "PeekScreen": {
- "Id": "PeekScreen",
- "CustomData": {}
+ "MirrorChyanCdkError": {
+ "Id": "MirrorChyanCdkError",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "MirrorChyanFirstUse": {
+ "Id": "MirrorChyanFirstUse",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"PioneerDebug": {
"Id": "PioneerDebug",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"PioneerSuperTest": {
"Id": "PioneerSuperTest",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "MapOutdated": {
+ "Id": "MapOutdated",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "CustomizationMaster": {
+ "Id": "CustomizationMaster",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "Martian": {
+ "Id": "Martian",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "PeekScreen": {
+ "Id": "PeekScreen",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"QuickCloser": {
"Id": "QuickCloser",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"RealGacha": {
"Id": "RealGacha",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"RecruitNoSixStarStreak": {
"Id": "RecruitNoSixStarStreak",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
- "Rules": {
- "Id": "Rules",
- "CustomData": {}
+ "SnapshotChallenge800": {
+ "Id": "SnapshotChallenge800",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "SnapshotChallenge999": {
+ "Id": "SnapshotChallenge999",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"TacticalRetreat": {
"Id": "TacticalRetreat",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "CongratulationError": {
+ "Id": "CongratulationError",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"UnexpectedCrash": {
"Id": "UnexpectedCrash",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "Rules": {
+ "Id": "Rules",
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
},
"VersionClick": {
"Id": "VersionClick",
- "CustomData": {}
+ "CustomData": {},
+ "MedalColor": "#FF6B4C2B"
+ },
+ "Lucky": {
+ "Id": "Lucky",
+ "MedalColor": "#FF6B4C2B"
}
}
\ No newline at end of file
diff --git a/src/MaaWpfGui/Constants/Enums.cs b/src/MaaWpfGui/Constants/Enums.cs
index e203726a81..083c700926 100644
--- a/src/MaaWpfGui/Constants/Enums.cs
+++ b/src/MaaWpfGui/Constants/Enums.cs
@@ -72,5 +72,43 @@ namespace MaaWpfGui.Constants
///
Undivided = 1,
}
+
+ public enum AchievementCategory
+ {
+ ///
+ /// 基础使用类
+ ///
+ BasicUsage,
+
+ ///
+ /// 功能探索类
+ ///
+ FeatureExploration,
+
+ ///
+ /// 自动战斗
+ ///
+ AutoBattle,
+
+ ///
+ /// 搞笑/梗类成就
+ ///
+ Humor,
+
+ ///
+ /// BUG 相关
+ ///
+ BugRelated,
+
+ ///
+ /// 彩蛋类
+ ///
+ EasterEgg,
+
+ ///
+ /// 超级稀有!
+ ///
+ Rare,
+ }
}
}
diff --git a/src/MaaWpfGui/Helper/AchievementTrackerHelper.cs b/src/MaaWpfGui/Helper/AchievementTrackerHelper.cs
index f6abb4c658..191f90083b 100644
--- a/src/MaaWpfGui/Helper/AchievementTrackerHelper.cs
+++ b/src/MaaWpfGui/Helper/AchievementTrackerHelper.cs
@@ -21,8 +21,8 @@ using HandyControl.Controls;
using HandyControl.Data;
using MaaWpfGui.Constants;
using MaaWpfGui.Models;
-using Newtonsoft.Json.Linq;
using Stylet;
+using static MaaWpfGui.Constants.Enums;
namespace MaaWpfGui.Helper
{
@@ -82,6 +82,7 @@ namespace MaaWpfGui.Helper
Achievements = _achievements
.OrderByDescending(kv => kv.Value.IsUnlocked) // 已解锁优先
.ThenBy(kv => kv.Value.IsHidden) // 隐藏排后面
+ .ThenBy(kv => kv.Value.Category) // 按类别分组
.ThenBy(kv => kv.Value.Id) // 最后按 Id
.ToDictionary(kv => kv.Key, kv => kv.Value);
@@ -135,7 +136,7 @@ namespace MaaWpfGui.Helper
Message = $"{LocalizationHelper.GetString("AchievementCelebrate")}: {achievement.Title}\n{achievement.Description}",
StaysOpen = staysOpen,
IconKey = "HangoverGeometry",
- IconBrushKey = achievement.IsHidden ? "HiddenMedalBrush" : "NormalMedalBrush",
+ IconBrushKey = $"AchievementBrush.{achievement.Category}",
};
ShowInfo(growlInfo);
}
@@ -253,73 +254,99 @@ namespace MaaWpfGui.Helper
public Achievement? Get(string id) => _achievements.GetValueOrDefault(id);
+ #region 工厂函数
+
+ private static Achievement BasicUsage(string id, int? target = null, bool isHidden = false)
+ => new() { Id = id, Target = target, IsHidden = isHidden, Category = AchievementCategory.BasicUsage };
+
+ private static Achievement FeatureExploration(string id, int? target = null, bool isHidden = false)
+ => new() { Id = id, Target = target, IsHidden = isHidden, Category = AchievementCategory.FeatureExploration };
+
+ private static Achievement AutoBattle(string id, int? target = null, bool isHidden = false)
+ => new() { Id = id, Target = target, IsHidden = isHidden, Category = AchievementCategory.AutoBattle };
+
+ private static Achievement Humor(string id, int? target = null, bool isHidden = false)
+ => new() { Id = id, Target = target, IsHidden = isHidden, Category = AchievementCategory.Humor };
+
+ private static Achievement BugRelated(string id, int? target = null, bool isHidden = false)
+ => new() { Id = id, Target = target, IsHidden = isHidden, Category = AchievementCategory.BugRelated };
+
+ private static Achievement EasterEgg(string id, int? target = null, bool isHidden = false)
+ => new() { Id = id, Target = target, IsHidden = isHidden, Category = AchievementCategory.EasterEgg };
+
+ private static Achievement Rare(string id, int? target = null, bool isHidden = false)
+ => new() { Id = id, Target = target, IsHidden = isHidden, Category = AchievementCategory.Rare };
+
+ #endregion
+
private readonly Achievement[] _allAchievements =
[
#region 基础使用类
- new() { Id = AchievementIds.SanitySpender1, Target = 10 }, // 刷理智次数
- new() { Id = AchievementIds.SanitySpender2, Target = 100 },
- new() { Id = AchievementIds.SanitySpender3, Target = 1000 },
+ BasicUsage(id: AchievementIds.SanitySpender1, target: 10), // 刷理智次数
+ BasicUsage(id: AchievementIds.SanitySpender2, target: 100),
+ BasicUsage(id: AchievementIds.SanitySpender3, target: 1000),
- new() { Id = AchievementIds.SanitySaver1, Target = 1 }, // 刷理智次数
- new() { Id = AchievementIds.SanitySaver2, Target = 10 },
- new() { Id = AchievementIds.SanitySaver3, Target = 50 },
+ BasicUsage(id: AchievementIds.SanitySaver1, target: 1), // 刷理智次数
+ BasicUsage(id: AchievementIds.SanitySaver2, target: 10),
+ BasicUsage(id: AchievementIds.SanitySaver3, target: 50),
- new() { Id = AchievementIds.FirstLaunch }, // 首次启动
- new() { Id = AchievementIds.SanityExpire, Target = 8 }, // 单次消耗 8 瓶快过期的理智药
- new() { Id = AchievementIds.OverLimitAgent, Target = 100, IsHidden = true }, // 单次代理 100 关
+ BasicUsage(id: AchievementIds.FirstLaunch), // 首次启动
+ BasicUsage(id: AchievementIds.SanityExpire, target: 8), // 单次消耗 8 瓶快过期的理智药
+ BasicUsage(id: AchievementIds.OverLimitAgent, target: 100, isHidden: true), // 单次代理 100 关
#endregion
#region 功能探索类
- new() { Id = AchievementIds.ScheduleMaster1, Target = 1 }, // 定时执行
- new() { Id = AchievementIds.ScheduleMaster2, Target = 100 },
+ FeatureExploration(id: AchievementIds.ScheduleMaster1, target: 1), // 定时执行
+ FeatureExploration(id: AchievementIds.ScheduleMaster2, target: 100),
- new() { Id = AchievementIds.MirrorChyanFirstUse, IsHidden = true }, // 第一次成功使用 MirrorChyan 下载
- new() { Id = AchievementIds.MirrorChyanCdkError, IsHidden = true }, // MirrorChyan CDK 错误
+ FeatureExploration(id: AchievementIds.MirrorChyanFirstUse, isHidden: true), // 第一次成功使用 MirrorChyan 下载
+ FeatureExploration(id: AchievementIds.MirrorChyanCdkError, isHidden: true), // MirrorChyan CDK 错误
- new() { Id = AchievementIds.PioneerTest }, // 将 MAA 更新至公测版
- new() { Id = AchievementIds.PioneerSuperTest, IsHidden = true }, // 将 MAA 更新至内测版(隐藏)
- new() { Id = AchievementIds.PioneerDebug, IsHidden = true }, // 使用未发布版本的 MAA(隐藏)
+ FeatureExploration(id: AchievementIds.PioneerTest), // 将 MAA 更新至公测版
+ FeatureExploration(id: AchievementIds.PioneerSuperTest, isHidden: true), // 将 MAA 更新至内测版(隐藏)
+ FeatureExploration(id: AchievementIds.PioneerDebug, isHidden: true), // 使用未发布版本的 MAA(隐藏)
- new() { Id = AchievementIds.MosquitoLeg, Target = 5 }, // 使用「借助战打 OF-1」功能超过5次
+ FeatureExploration(id: AchievementIds.MosquitoLeg, target: 5), // 使用「借助战打 OF-1」功能超过5次
#endregion
#region 自动战斗
- new() { Id = AchievementIds.UseCopilot1, Target = 1 }, // 自动战斗
- new() { Id = AchievementIds.UseCopilot2, Target = 10 },
- new() { Id = AchievementIds.UseCopilot3, Target = 100 },
+ AutoBattle(id: AchievementIds.UseCopilot1, target: 1), // 自动战斗
+ AutoBattle(id: AchievementIds.UseCopilot2, target: 10),
+ AutoBattle(id: AchievementIds.UseCopilot3, target: 100),
- new() { Id = AchievementIds.MapOutdated, IsHidden = true }, // 提示需要更新地图资源
- new() { Id = AchievementIds.Irreplaceable }, // 自动编队缺少至少两名干员
+ AutoBattle(id: AchievementIds.MapOutdated, isHidden: true), // 提示需要更新地图资源
+ AutoBattle(id: AchievementIds.Irreplaceable), // 自动编队缺少至少两名干员
#endregion
#region 搞笑/梗类成就
- new() { Id = AchievementIds.SnapshotChallenge999, IsHidden = true }, // 平均截图用时超过 800ms(高 ping 战士)
- new() { Id = AchievementIds.SnapshotChallenge800, IsHidden = true }, // 平均截图用时在 400ms 到 800ms 之间(是不是有点太慢了)
- new() { Id = AchievementIds.SnapshotChallenge400 }, // 平均截图用时小于 400ms(截图挑战 · Normal)
- new() { Id = AchievementIds.SnapshotChallenge100 }, // 平均截图用时小于 100ms(截图挑战 · Fast)
- new() { Id = AchievementIds.SnapshotChallenge10 }, // 平均截图用时小于 10ms(截图挑战 · Ultra)
+ Humor(id: AchievementIds.SnapshotChallenge999, isHidden: true), // 平均截图用时超过 800ms(高 ping 战士)
+ Humor(id: AchievementIds.SnapshotChallenge800, isHidden: true), // 平均截图用时在 400ms 到 800ms 之间(是不是有点太慢了)
+ Humor(id: AchievementIds.SnapshotChallenge400), // 平均截图用时小于 400ms(截图挑战 · Normal)
+ Humor(id: AchievementIds.SnapshotChallenge100), // 平均截图用时小于 100ms(截图挑战 · Fast)
+ Humor(id: AchievementIds.SnapshotChallenge10), // 平均截图用时小于 10ms(截图挑战 · Ultra)
- new() { Id = AchievementIds.QuickCloser, IsHidden = true }, // 快速关闭弹窗
- new() { Id = AchievementIds.TacticalRetreat, IsHidden = true }, // 停止任务
- new() { Id = AchievementIds.RealGacha, IsHidden = true }, // 真正的抽卡
- new() { Id = AchievementIds.PeekScreen, IsHidden = true }, // 窥屏
- new() { Id = AchievementIds.CustomizationMaster, IsHidden = true }, // 自定义背景
- new() { Id = AchievementIds.Martian, IsHidden = true }, // 90 天没更新
- new() { Id = AchievementIds.RecruitNoSixStar, Target = 100 }, // 公招中累计 100 次没出现六星tag
- new() { Id = AchievementIds.RecruitNoSixStarStreak, Target = 100, IsHidden = true }, // 公招中连续 100 次没出现六星tag
+ Humor(id: AchievementIds.QuickCloser, isHidden: true), // 快速关闭弹窗
+ Humor(id: AchievementIds.TacticalRetreat, isHidden: true), // 停止任务
+ Humor(id: AchievementIds.RealGacha, isHidden: true), // 真正的抽卡
+ Humor(id: AchievementIds.PeekScreen, isHidden: true), // 窥屏
+ Humor(id: AchievementIds.CustomizationMaster, isHidden: true), // 自定义背景
+ Humor(id: AchievementIds.Martian, isHidden: true), // 90 天没更新
+ Humor(id: AchievementIds.RecruitNoSixStar, target: 100), // 公招中累计 100 次没出现六星tag
+ Humor(id: AchievementIds.RecruitNoSixStarStreak, target: 100, isHidden: true), // 公招中连续 100 次没出现六星tag
#endregion
#region BUG 相关
- new() { Id = AchievementIds.CongratulationError, IsHidden = true }, // 喜报
- new() { Id = AchievementIds.UnexpectedCrash, IsHidden = true }, // 不速之客
- new() { Id = AchievementIds.ProblemFeedback }, // 问题反馈
+ BugRelated(id: AchievementIds.CongratulationError, isHidden: true), // 喜报
+ BugRelated(id: AchievementIds.UnexpectedCrash, isHidden: true), // 不速之客
+ BugRelated(id: AchievementIds.ProblemFeedback), // 问题反馈
#endregion
#region 彩蛋类
- new() { Id = AchievementIds.Rules, IsHidden = true }, // 我会一直注视着你
- new() { Id = AchievementIds.VersionClick, IsHidden = true }, // 这也能点?
- new() { Id = AchievementIds.Lucky, IsHidden = true }, // 启动 MAA 时有极小概率触发
+ EasterEgg(id: AchievementIds.Rules, isHidden: true), // 我会一直注视着你
+ EasterEgg(id: AchievementIds.VersionClick, isHidden: true), // 这也能点?
+
+ Rare(id: AchievementIds.Lucky, isHidden: true), // 启动 MAA 时有极小概率触发
#endregion
];
diff --git a/src/MaaWpfGui/Models/Achievement.cs b/src/MaaWpfGui/Models/Achievement.cs
index 186611e84d..866013e767 100644
--- a/src/MaaWpfGui/Models/Achievement.cs
+++ b/src/MaaWpfGui/Models/Achievement.cs
@@ -17,6 +17,7 @@ using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
+using MaaWpfGui.Constants;
using MaaWpfGui.Helper;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -72,14 +73,34 @@ namespace MaaWpfGui.Models
[JsonIgnore]
public int? Target { get; set; } = null; // 可选目标值
+ [JsonIgnore]
+ public Enums.AchievementCategory Category { get; set; } // 分组
+
+ [JsonIgnore]
+ public bool IsRare => Category == Enums.AchievementCategory.Rare;
+
[JsonIgnore]
public SolidColorBrush MedalBrush
{
get
{
- var key = !IsUnlocked ? "LockedMedalBrush"
- : IsHidden ? "HiddenMedalBrush"
- : "NormalMedalBrush";
+ string key;
+ if (IsRare)
+ {
+ key = "AchievementBrush.Rare";
+ }
+ else if (!IsUnlocked)
+ {
+ key = "LockedMedalBrush";
+ }
+ else if (IsHidden)
+ {
+ key = "HiddenMedalBrush";
+ }
+ else
+ {
+ key = $"AchievementBrush.{Category}";
+ }
if (Application.Current.Resources[key] is SolidColorBrush brush)
{
diff --git a/src/MaaWpfGui/Res/Themes/Dark.xaml b/src/MaaWpfGui/Res/Themes/Dark.xaml
index af3a191eec..f41c2b85f6 100644
--- a/src/MaaWpfGui/Res/Themes/Dark.xaml
+++ b/src/MaaWpfGui/Res/Themes/Dark.xaml
@@ -52,6 +52,14 @@
+
+
+
+
+
+
+
+
diff --git a/src/MaaWpfGui/Res/Themes/Light.xaml b/src/MaaWpfGui/Res/Themes/Light.xaml
index 8845e271aa..0ada2febe5 100644
--- a/src/MaaWpfGui/Res/Themes/Light.xaml
+++ b/src/MaaWpfGui/Res/Themes/Light.xaml
@@ -31,6 +31,13 @@
+
+
+
+
+
+
+