rft: 关卡候选列表刷新 & 关卡选择下拉列表刷新 (#15562)

* rft: 无效关卡重置

* fix: 显示翻转

* fix: 无效关卡开放状态错误

* fix: 无效关卡被错误重置

* feat: 自定义剿灭关卡将会同步修改关卡选择下拉框中的剿灭模式显示名

* perf: 修改任务参数快速退出

* i18n: invalid stage

* fix: 刷理智任务在LinkStart后修改关卡无法生效

* i18n: KR

* i18n: EN

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* i18n: JP

* i18n: zh-tw

---------

Co-authored-by: HX3N <scarlet7518@gmail.com>
Co-authored-by: Constrat <56174894+Constrat@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Manicsteiner <Manicsteiner@outlook.com>
Co-authored-by: momomochi987 <as99us301@gmail.com>
This commit is contained in:
Status102
2026-02-01 22:59:30 +08:00
committed by GitHub
parent 583c52ec13
commit 1879c290ad
9 changed files with 138 additions and 46 deletions

View File

@@ -16,6 +16,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
using MaaWpfGui.Constants.Enums;
using static MaaWpfGui.Main.AsstProxy;
namespace MaaWpfGui.Configuration.Single.MaaTask;
@@ -127,6 +128,8 @@ public class FightTask : BaseTask, IJsonOnDeserialized
/// </summary>
public bool HideSeries { get; set; }
public FightStageResetMode StageResetMode { get; set; } = FightStageResetMode.Current;
/// <summary>
/// Gets or sets a value indicating whether 是否启用周计划
/// </summary>

View File

@@ -0,0 +1,27 @@
// <copyright file="FightStageResetMode.cs" company="MaaAssistantArknights">
// Part of the MaaWpfGui project, maintained by the MaaAssistantArknights team (Maa Team)
// Copyright (C) 2021-2025 MaaAssistantArknights Contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License v3.0 only as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY
// </copyright>
namespace MaaWpfGui.Constants.Enums;
public enum FightStageResetMode
{
/// <summary>
/// 当前 / 上次
/// </summary>
Current,
/// <summary>
/// 无效关卡
/// </summary>
Invalid,
}

View File

@@ -587,6 +587,7 @@ Then delete the entries corresponding to the paths.
<system:String x:Key="UseAlternateStage">Use alternative stage</system:String>
<system:String x:Key="UseExpiringMedicine">Unlimited use of expiring (&lt;48h) sanity potion</system:String>
<system:String x:Key="HideUnavailableStage">Hide today's not open stages</system:String>
<system:String x:Key="FightStageResetMode">Unopened stage is reset to</system:String>
<system:String x:Key="HideSeries">Hide series</system:String>
<system:String x:Key="MainViewButtonFeature">Variable function button</system:String>
<system:String x:Key="CustomStageCode">Manual entry of stage names</system:String>
@@ -738,14 +739,15 @@ If the number of battles is not enough to complete the set multiplier (such as o
• {key=NotSwitch}:
Do not adjust the proxy multiplier setting in the game</system:String>
<system:String x:Key="StageSelect">Stage</system:String>
<system:String x:Key="StageSelect2">Alternative</system:String>
<system:String x:Key="AddStage">Add stage</system:String>
<system:String x:Key="StageSelect2">Candidates</system:String>
<system:String x:Key="AddStage">Add candidate</system:String>
<system:String x:Key="RemainingSanityStage">Remaining Sanity</system:String>
<system:String x:Key="NoUse">No Use</system:String>
<!--<system:String x:Key="Amend">Amend</system:String>-->
<!--<system:String x:Key="CurrentStage">Current Stage</system:String>-->
<!--<system:String x:Key="LastBattle">Last Battle</system:String>-->
<system:String x:Key="DefaultStage">Cur/Last</system:String>
<system:String x:Key="InvalidStage">Invalid</system:String>
<system:String x:Key="ClosedStage">The event is not open</system:String>
<system:String x:Key="UnsupportedStages">Unsupported stages</system:String>
<system:String x:Key="LowVersion">Old Version, Update required</system:String>

View File

@@ -586,7 +586,8 @@ HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Notifications\Settin
<system:String x:Key="AllowUseStoneSaveWarning">この機能は危険な機能と見なされます。「{key=Confirm}」ボタンを押すと、リスクを理解し、受け入れることに同意したと見なされます。</system:String>
<system:String x:Key="UseAlternateStage">代替ステージを選択可能にする</system:String>
<system:String x:Key="UseExpiringMedicine">48時間以内に期限が切れる回復剤を無制限に使用</system:String>
<system:String x:Key="HideUnavailableStage">当日開放されないステージを隠す</system:String>
<system:String x:Key="HideUnavailableStage">リストに当日開放されないステージを隠す</system:String>
<system:String x:Key="FightStageResetMode">未開放のレベルをこれにリセットする</system:String>
<system:String x:Key="HideSeries">連戦回数を隠します</system:String>
<system:String x:Key="MainViewButtonFeature">スタート画面に表示する便利ボタン</system:String>
<system:String x:Key="CustomStageCode">ステージ名を入力する</system:String>
@@ -747,6 +748,7 @@ C:\\leidian\\LDPlayer9
<!--<system:String x:Key="CurrentStage">当前关卡</system:String> -->
<!--<system:String x:Key="LastBattle">上次作战</system:String>-->
<system:String x:Key="DefaultStage">現在/前回</system:String>
<system:String x:Key="InvalidStage">無効なレベル</system:String>
<system:String x:Key="ClosedStage">ステージが未公開か既に終了している</system:String>
<system:String x:Key="UnsupportedStages">未サポートステージ</system:String>
<system:String x:Key="LowVersion">バージョンの更新が必要</system:String>

View File

@@ -587,6 +587,7 @@ HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Notifications\Settin
<system:String x:Key="UseAlternateStage">대체 스테이지 사용</system:String>
<system:String x:Key="UseExpiringMedicine">48시간 미만 이성 회복제 사용</system:String>
<system:String x:Key="HideUnavailableStage">미개방 스테이지 숨기기</system:String>
<system:String x:Key="FightStageResetMode">미개방 스테이지 재설정</system:String>
<system:String x:Key="HideSeries">{key=Series} 숨기기</system:String>
<system:String x:Key="MainViewButtonFeature">메인 화면 버튼의 기능</system:String>
<system:String x:Key="CustomStageCode">스테이지 코드 수동 입력</system:String>
@@ -748,7 +749,8 @@ C:\\leidian\\LDPlayer9
<!--<system:String x:Key="CurrentStage">현재 스테이지</system:String>
<system:String x:Key="LastBattle">최근 작전</system:String>-->
<system:String x:Key="DefaultStage">현재/최근</system:String>
<system:String x:Key="ClosedStage">이벤트가 닫혀 있습니다</system:String>
<system:String x:Key="InvalidStage">잘못된 스테이지</system:String>
<system:String x:Key="ClosedStage">미개방 스테이지</system:String>
<system:String x:Key="UnsupportedStages">미지원 스테이지</system:String>
<system:String x:Key="LowVersion">낮은 버전</system:String>
<system:String x:Key="MinimumRequirements" xml:space="preserve">최소 요구사항: </system:String>

View File

@@ -586,7 +586,8 @@ HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Notifications\Settin
<system:String x:Key="AllowUseStoneSaveWarning">该功能属于危险功能。按下 「{key=Confirm}」 键即视为你了解并愿意承担可能出现的风险。</system:String>
<system:String x:Key="UseAlternateStage">使用备选关卡</system:String>
<system:String x:Key="UseExpiringMedicine">无限吃 48 小时内过期的理智药</system:String>
<system:String x:Key="HideUnavailableStage">隐藏当日不开放关卡</system:String>
<system:String x:Key="HideUnavailableStage">下拉框中隐藏当日不开放关卡</system:String>
<system:String x:Key="FightStageResetMode">未开放关卡重置为</system:String>
<system:String x:Key="HideSeries">隐藏代理倍率</system:String>
<system:String x:Key="MainViewButtonFeature">主界面可选择按钮功能</system:String>
<system:String x:Key="CustomStageCode">手动输入关卡名</system:String>
@@ -738,15 +739,16 @@ C:\\leidian\\LDPlayer9。\n
• {key=NotSwitch}:
不调整游戏内代理倍率设定</system:String>
<system:String x:Key="StageSelect">关卡选择</system:String>
<system:String x:Key="StageSelect2">关卡备选</system:String>
<system:String x:Key="AddStage">添加关卡</system:String>
<system:String x:Key="StageSelect">关卡指定</system:String>
<system:String x:Key="StageSelect2">候选关卡</system:String>
<system:String x:Key="AddStage">添加候选</system:String>
<system:String x:Key="RemainingSanityStage">剩余理智</system:String>
<system:String x:Key="NoUse">不使用</system:String>
<!--<system:String x:Key="Amend">修改</system:String>-->
<!--<system:String x:Key="CurrentStage">当前关卡</system:String> -->
<!--<system:String x:Key="LastBattle">上次作战</system:String>-->
<system:String x:Key="DefaultStage">当前/上次</system:String>
<system:String x:Key="InvalidStage">无效关卡</system:String>
<system:String x:Key="ClosedStage">活动未开放</system:String>
<system:String x:Key="UnsupportedStages">不支持的关卡</system:String>
<system:String x:Key="LowVersion">版本过低</system:String>

View File

@@ -586,7 +586,8 @@ HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Notifications\Settin
<system:String x:Key="AllowUseStoneSaveWarning">該功能屬於危險功能。按下 「{key=Confirm}」 鍵即視為您了解並願意承擔可能出現的風險。</system:String>
<system:String x:Key="UseAlternateStage">使用備選關卡</system:String>
<system:String x:Key="UseExpiringMedicine">無限吃 48 小時內過期的理智藥</system:String>
<system:String x:Key="HideUnavailableStage">隱藏當日不開放關卡</system:String>
<system:String x:Key="HideUnavailableStage">下拉選單中隱藏當日不開放關卡</system:String>
<system:String x:Key="FightStageResetMode">未開放關卡重設為</system:String>
<system:String x:Key="HideSeries">隱藏代理倍率</system:String>
<system:String x:Key="MainViewButtonFeature">主介面可選擇按鈕功能</system:String>
<system:String x:Key="CustomStageCode">手動輸入關卡名稱</system:String>
@@ -740,13 +741,14 @@ C:\\leidian\\LDPlayer9\n
不調整遊戲內代理倍率設定</system:String>
<system:String x:Key="StageSelect">關卡選擇</system:String>
<system:String x:Key="StageSelect2">備選</system:String>
<system:String x:Key="AddStage">新增關卡</system:String>
<system:String x:Key="AddStage">新增備選</system:String>
<system:String x:Key="RemainingSanityStage">剩餘理智</system:String>
<system:String x:Key="NoUse">不選擇</system:String>
<!--<system:String x:Key="Amend">修改</system:String>-->
<!--<system:String x:Key="CurrentStage">目前關卡</system:String>-->
<!--<system:String x:Key="LastBattle">上次作戰</system:String>-->
<system:String x:Key="DefaultStage">目前/上次</system:String>
<system:String x:Key="InvalidStage">無效關卡</system:String>
<system:String x:Key="ClosedStage">活動未開放</system:String>
<system:String x:Key="UnsupportedStages">不支援的關卡</system:String>
<system:String x:Key="LowVersion">版本過低</system:String>

View File

@@ -22,6 +22,7 @@ using JetBrains.Annotations;
using MaaWpfGui.Configuration.Factory;
using MaaWpfGui.Configuration.Single.MaaTask;
using MaaWpfGui.Constants;
using MaaWpfGui.Constants.Enums;
using MaaWpfGui.Helper;
using MaaWpfGui.Models;
using MaaWpfGui.Models.AsstTasks;
@@ -91,6 +92,8 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
{ "炭", "SK-5" },
};
private readonly StageSourceItem InvalidStage = new() { Display = LocalizationHelper.GetString("InvalidStage"), Value = "__INVALID__", IsOpen = false, IsVisible = false };
public ObservableCollection<StagePlanItem> StagePlan { get => field; set => SetAndNotify(ref field, value); } = [new()];
// UI 绑定的方法
@@ -386,11 +389,11 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
foreach (var task in ConfigFactory.CurrentConfig.TaskQueue.OfType<FightTask>())
{
if (AllDrops.FirstOrDefault(i => i.Value == task.DropId) is not { } item)
{
{
task.DropId = string.Empty;
}
}
}
}
/// <summary>
/// Gets or private sets the list of drops.
@@ -461,7 +464,10 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
public string AnnihilationStage
{
get => GetTaskConfig<FightTask>().AnnihilationStage;
set => SetTaskConfig<FightTask>(t => t.AnnihilationStage == value, t => t.AnnihilationStage = value);
set {
SetTaskConfig<FightTask>(t => t.AnnihilationStage == value, t => t.AnnihilationStage = value);
StageListSource.FirstOrDefault(i => i.Value == "Annihilation")?.Display = UseCustomAnnihilation ? (AnnihilationModeList.FirstOrDefault(i => i.Value == value).Key ?? LocalizationHelper.GetString("Annihilation.Current")) : LocalizationHelper.GetString("Annihilation.Current");
}
}
/// <summary>
@@ -484,6 +490,7 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
if (value)
{
HideUnavailableStage = false;
StageResetMode = FightStageResetMode.Invalid;
}
else
{
@@ -549,14 +556,27 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
if (value)
{
UseAlternateStage = false;
StageResetMode = FightStageResetMode.Current;
}
if (update)
{
UpdateStageList();
RefreshStageList();
}
}
}
public List<GenericCombinedData<FightStageResetMode>> StageResetModeList { get; } =
[
new() { Display = LocalizationHelper.GetString("DefaultStage"), Value = FightStageResetMode.Current },
new() { Display = LocalizationHelper.GetString("InvalidStage"), Value = FightStageResetMode.Invalid },
];
public FightStageResetMode StageResetMode
{
get => GetTaskConfig<FightTask>().StageResetMode;
set => SetTaskConfig<FightTask>(t => t.StageResetMode == value, t => t.StageResetMode = value);
}
/// <summary>
/// Gets or sets a value indicating whether to hide series.
/// </summary>
@@ -617,8 +637,9 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
public static string? GetFightStage(IEnumerable<string> stageNames)
{
var stage = stageNames.FirstOrDefault(Instances.TaskQueueViewModel.IsStageOpen);
stage ??= stageNames.FirstOrDefault();
var list = stageNames.Where(i => i != Instance.InvalidStage.Value);
var stage = list.FirstOrDefault(Instances.TaskQueueViewModel.IsStageOpen);
stage ??= list.FirstOrDefault();
return stage;
}
@@ -633,7 +654,7 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
{
fight.StagePlan.Add(string.Empty);
}
UpdateStageList(); // 临时修复, 应为同步
RefreshStageList();
RefreshCurrentStagePlan();
RefreshWeeklySchedule();
RefreshDropName();
@@ -680,12 +701,12 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
private bool? SetFightParams()
{
if (TaskSettingVisibilityInfo.CurrentTask is not FightTask fight)
if (IsRefreshingUI || TaskSettingVisibilityInfo.CurrentTask is not FightTask fight)
{
return null;
}
if (ConfigFactory.CurrentConfig.TaskQueue.IndexOf(fight) is int index && index > -1)
if (ConfigFactory.CurrentConfig.TaskQueue.IndexOf(fight) is int index && index > -1 && Instances.TaskQueueViewModel.TaskItemViewModels[index].TaskId > 0)
{
return SerializeTask(fight, Instances.TaskQueueViewModel.TaskItemViewModels[index].TaskId);
}
@@ -695,7 +716,7 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
public override bool? SerializeTask(BaseTask? baseTask, int? taskId = null)
{
if (baseTask is not FightTask fight)
if (baseTask is not FightTask fight || taskId is int and <= 0)
{
return null;
}
@@ -766,39 +787,48 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
Execute.PostToUIThreadAsync(() => {
_logger.Information("Updating stage list...");
using var scope = _lock.EnterScope();
bool isFightTaskShow = TaskSettingVisibilityInfo.CurrentTask is FightTask;
var hideUnavailble = isFightTaskShow && HideUnavailableStage;
var stageList = Instances.StageManager.GetStageList().ToList();
var listCurrent = StagePlan.Select(i => i.Value).ToList();
var listSource = stageList.Select(i => new StageSourceItem() { Display = i.Display, Value = i.Value, IsVisible = !hideUnavailble || i.IsStageOpen(Instances.TaskQueueViewModel.CurDayOfWeek), IsOpen = Instances.StageManager.GetStageList().FirstOrDefault(p => p.Value == i.Value)?.IsStageOpen(Instances.TaskQueueViewModel.CurDayOfWeek) ?? true }).ToList();
if (isFightTaskShow)
{
foreach (var item in listCurrent.Where(i => !listSource.Any(p => p.Value == i))) // 补未开放进来
{
listSource.Add(new StageSourceItem() { Display = item, Value = item, IsOpen = false, IsVisible = false });
}
}
StageListSource = new ObservableCollection<StageSourceItem>(listSource);
if (TaskSettingVisibilityInfo.CurrentTask is FightTask current)
{
current.StagePlan = listCurrent;
}
var stageList = Instances.StageManager.GetStageList();
RefreshStageList();
foreach (var task in ConfigFactory.CurrentConfig.TaskQueue.Where(i => i is FightTask fight && !fight.IsStageManually).OfType<FightTask>())
{
var removeList = task.StagePlan.Where(i => !stageList.Any(p => p.Value == i)).ToList();
if (removeList.Count != 0)
for (int i = 0; i < task.StagePlan.Count; i++)
{
_logger.Information("Removed non-existing stage from plan: {Stage}", removeList);
task.StagePlan = [.. task.StagePlan.Where(i => stageList.Any(p => p.Value == i))];
var stage = task.StagePlan[i];
if (stage != InvalidStage.Value && !stageList.Any(p => p.Value == stage))
{
task.StagePlan[i] = task.StageResetMode switch {
FightStageResetMode.Current => string.Empty,
FightStageResetMode.Invalid => InvalidStage.Value,
_ => string.Empty,
};
_logger.Information("Reset non-existing stage from plan: {Stage} to {}", stage, task.StagePlan[i]);
}
}
}
RefreshCurrentStagePlan();
});
}
private void RefreshStageList()
{
if (TaskSettingVisibilityInfo.CurrentTask is not FightTask current)
{
return;
}
var stageList = Instances.StageManager.GetStageList().ToList();
var listCurrent = StagePlan.Select(i => i.Value).ToList();
var listSource = stageList.Select(i => new StageSourceItem() { Display = i.Display, Value = i.Value, IsVisible = !HideUnavailableStage || i.IsStageOpen(Instances.TaskQueueViewModel.CurDayOfWeek), IsOpen = Instances.StageManager.GetStageList().FirstOrDefault(p => p.Value == i.Value)?.IsStageOpen(Instances.TaskQueueViewModel.CurDayOfWeek) ?? true }).ToList();
foreach (var item in listCurrent.Where(i => !listSource.Any(p => p.Value == i))) // 补未开放进来
{
listSource.Add(new StageSourceItem() { Display = item, Value = item, IsOpen = false, IsVisible = false });
}
listSource.Add(InvalidStage); // 无效关卡
listSource.FirstOrDefault(i => i.Value == "Annihilation")?.Display = current.UseCustomAnnihilation ? (AnnihilationModeList.FirstOrDefault(i => i.Value == current.AnnihilationStage).Key ?? LocalizationHelper.GetString("Annihilation.Current")) : LocalizationHelper.GetString("Annihilation.Current");
StageListSource = new ObservableCollection<StageSourceItem>(listSource);
current.StagePlan = listCurrent; // StageListSource更新后, 恢复StagePlan
}
private void RefreshCurrentStagePlan()
{
if (TaskSettingVisibilityInfo.CurrentTask is not FightTask)
@@ -895,7 +925,7 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
public class StageSourceItem : PropertyChangedBase
{
public string Display { get; set; } = string.Empty;
public string Display { get => field; set => SetAndNotify(ref field, value); } = string.Empty;
public string Value { get; set; } = string.Empty;
@@ -925,7 +955,15 @@ public class FightSettingsUserControlModel : TaskSettingsViewModel
return;
}
IsOpen = Instances.StageManager.GetStageList().FirstOrDefault(p => p.Value == value)?.IsStageOpen(Instances.TaskQueueViewModel.CurDayOfWeek) ?? true;
if (value == Instance.InvalidStage.Value)
{
IsOpen = false;
}
else
{
IsOpen = Instances.StageManager.GetStageList().FirstOrDefault(p => p.Value == value)?.IsStageOpen(Instances.TaskQueueViewModel.CurDayOfWeek) ?? true;
}
Instance.SetFightParams();
}
} = string.Empty;

View File

@@ -398,6 +398,20 @@
<CheckBox Content="{DynamicResource CustomStageCode}" IsChecked="{Binding CustomStageCode}" />
<controls:TooltipBlock TooltipText="{DynamicResource CustomStageCodeTip}" />
</StackPanel>
<StackPanel
Margin="0,6"
Orientation="Horizontal"
Visibility="{c:Binding !CustomStageCode}">
<controls:TextBlock VerticalAlignment="Center" Text="{DynamicResource FightStageResetMode}" />
<controls:TooltipBlock TooltipText="{DynamicResource CustomStageCodeTip}" />
<ComboBox
Width="100"
Margin="5,0,0,0"
DisplayMemberPath="Display"
ItemsSource="{Binding StageResetModeList}"
SelectedValue="{Binding StageResetMode}"
SelectedValuePath="Value" />
</StackPanel>
<CheckBox
Margin="0,10"
Content="{DynamicResource UseAlternateStage}"