//
// 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
//
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Windows;
using JetBrains.Annotations;
using MaaWpfGui.Configuration.Factory;
using MaaWpfGui.Configuration.Single.MaaTask;
using MaaWpfGui.Constants;
using MaaWpfGui.Helper;
using MaaWpfGui.Models;
using MaaWpfGui.Models.AsstTasks;
using MaaWpfGui.Services;
using MaaWpfGui.Utilities;
using MaaWpfGui.Utilities.ValueType;
using MaaWpfGui.ViewModels.UI;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serilog;
using Stylet;
using static MaaWpfGui.Main.AsstProxy;
namespace MaaWpfGui.ViewModels.UserControl.TaskQueue;
///
/// 理智作战
///
public class FightSettingsUserControlModel : TaskSettingsViewModel
{
private static readonly ILogger _logger = Log.ForContext();
private static readonly Lock _lock = new();
public static FightTimes? FightReport { get; set; }
public static SanityInfo? SanityReport { get; set; }
static FightSettingsUserControlModel()
{
Instance = new();
}
public FightSettingsUserControlModel()
{
foreach (var i in WeeklyScheduleSource)
{
i.PropertyChanged += (_, __) => SaveWeeklySchedule();
}
var item = new StagePlanItem();
item.PropertyChanged += (_, __) => SaveStagePlan();
StagePlan.Add(item);
}
public static FightSettingsUserControlModel Instance { get; }
///
/// Gets or private sets the list of stages.
///
public ObservableCollection StageListSource
{
get => field;
private set => SetAndNotify(ref field, value);
} = [];
private static readonly Dictionary _stageDictionary = new()
{
{ "AN", "Annihilation" },
{ "剿灭", "Annihilation" },
{ "CE", "CE-6" },
{ "龙门币", "CE-6" },
{ "LS", "LS-6" },
{ "经验", "LS-6" },
{ "狗粮", "LS-6" },
{ "CA", "CA-5" },
{ "技能", "CA-5" },
{ "AP", "AP-5" },
{ "红票", "AP-5" },
{ "SK", "SK-5" },
{ "碳", "SK-5" },
{ "炭", "SK-5" },
};
public ObservableCollection StagePlan { get => field; set => SetAndNotify(ref field, value); } = [new()];
// UI 绑定的方法
[UsedImplicitly]
public void AddStageToPlan()
{
var item = new StagePlanItem();
item.PropertyChanged += (_, __) => SaveStagePlan();
StagePlan.Add(item);
}
// UI 绑定的方法
[UsedImplicitly]
public void RemoveStageFromPlan(StagePlanItem plan)
{
if (StagePlan.Count == 1)
{
_logger.Warning("Attempted to remove the last stage from the plan. Operation aborted.");
return;
}
StagePlan.Remove(plan);
}
///
/// Gets or sets the stage1.
///
public string? Stage
{
get => field;
set {
if (field == value)
{
return;
}
if (CustomStageCode)
{
// 从后往前删
if (field?.Length != 3 && value != null)
{
value = ToUpperAndCheckStage(value);
}
}
SetAndNotify(ref field, value);
SetFightParams();
Instances.TaskQueueViewModel.UpdateDatePrompt();
}
}
///
/// Gets or sets a value indicating whether to use custom stage code.
///
public bool CustomStageCode
{
get => GetTaskConfig().IsStageManually;
set => SetTaskConfig(t => t.IsStageManually == value, t => t.IsStageManually = value);
}
///
/// Reset unsaved battle parameters.
///
/// The fight task.
public static void ResetFightVariables(FightTask? fight)
{
fight?.UseStone ??= false;
fight?.UseMedicine ??= false;
fight?.EnableTimesLimit ??= false;
fight?.EnableTargetDrop ??= false;
}
///
/// Gets or sets a value indicating whether to use medicine with null.
///
public bool? UseMedicine
{
get => GetTaskConfig().UseMedicine;
set {
if (!SetTaskConfig(t => t.UseMedicine == value, t => t.UseMedicine = value))
{
return;
}
if (value == false)
{
UseStoneDisplay = false;
}
SetFightParams();
}
}
///
/// Gets or sets the amount of medicine used.
///
public int MedicineNumber
{
get => GetTaskConfig().MedicineCount;
set {
if (!SetTaskConfig(t => t.MedicineCount == value, t => t.MedicineCount = value))
{
return;
}
SetFightParams();
}
}
public static string UseStoneString => LocalizationHelper.GetString("UseOriginitePrime");
///
/// Gets or sets a value indicating whether to use originiums with null.
///
public bool? UseStone
{
get => GetTaskConfig().UseStone;
set {
if (!AllowUseStoneSave && value == true)
{
value = null;
}
if (value != false)
{
MedicineNumber = 999;
if (UseMedicine == false)
{
UseMedicine = value;
}
}
SetFightParams();
SetTaskConfig(t => t.UseStone == value, t => t.UseStone = value);
}
}
///
/// Gets or sets a value indicating whether to use originiums.
///
// ReSharper disable once MemberCanBePrivate.Global
[PropertyDependsOn(nameof(UseStone))]
public bool UseStoneDisplay
{
get => UseStone != false;
set => UseStone = value;
}
///
/// Gets or sets the amount of originiums used.
///
public int StoneNumber
{
get => GetTaskConfig().StoneCount;
set {
if (!SetTaskConfig(t => t.StoneCount == value, t => t.StoneCount = value))
{
return;
}
SetFightParams();
}
}
///
/// Gets or sets a value indicating whether the number of times is limited with null.
///
public bool? HasTimesLimited
{
get => GetTaskConfig().EnableTimesLimit;
set {
if (!SetTaskConfig(t => t.EnableTimesLimit == value, t => t.EnableTimesLimit = value))
{
return;
}
SetFightParams();
}
}
///
/// Gets or sets the max number of times.
///
public int MaxTimes
{
get => GetTaskConfig().TimesLimit;
set {
if (!SetTaskConfig(t => t.TimesLimit == value, t => t.TimesLimit = value))
{
return;
}
SetFightParams();
}
}
public static Dictionary SeriesList { get; set; } = new()
{
{ "AUTO", 0 },
{ "6", 6 },
{ "5", 5 },
{ "4", 4 },
{ "3", 3 },
{ "2", 2 },
{ "1", 1 },
{ LocalizationHelper.GetString("NotSwitch"), -1 },
};
///
/// Gets or sets the max number of times.
///
public int Series
{
get => GetTaskConfig().Series;
set {
if (!SetTaskConfig(t => t.Series == value, t => t.Series = value))
{
return;
}
SetFightParams();
}
}
#region Drops
///
/// Gets or sets a value indicating whether the drops are specified.
///
public bool? IsSpecifiedDrops
{
get => GetTaskConfig().EnableTargetDrop;
set {
if (!SetTaskConfig(t => t.EnableTargetDrop == value, t => t.EnableTargetDrop = value))
{
return;
}
SetFightParams();
}
}
///
/// Gets the list of all drops.
///
private List AllDrops { get; } = [];
///
/// 关卡不可掉落的材料
///
private static readonly HashSet _excludedValues =
[
"3213", "3223", "3233", "3243", // 双芯片
"3253", "3263", "3273", "3283", // 双芯片
"7001", "7002", "7003", "7004", // 许可
"4004", "4005", // 凭证
"3105", "3131", "3132", "3133", // 龙骨/加固建材
"6001", // 演习券
"3141", "4002", // 源石
"32001", // 芯片助剂
"30115", // 聚合剂
"30125", // 双极纳米片
"30135", // D32钢
"30145", // 晶体电子单元
"30155", // 烧结核凝晶
"30165", // 重相位对映体
];
private void InitDrops()
{
AllDrops.Add(new() { Display = LocalizationHelper.GetString("NotSelected"), Value = string.Empty });
foreach (var (val, value) in ItemListHelper.ArkItems)
{
// 不是数字的东西都是正常关卡不会掉的(大概吧)
if (!int.TryParse(val, out _))
{
continue;
}
var dis = value.Name;
if (_excludedValues.Contains(val))
{
continue;
}
AllDrops.Add(new() { Display = dis, Value = val });
}
AllDrops.Sort((a, b) => string.Compare(a.Value, b.Value, StringComparison.Ordinal));
DropsList = [.. AllDrops];
if (AllDrops.FirstOrDefault(i => i.Value == DropsItemId) is { } item)
{
DropsItemName = item.Display;
NotifyOfPropertyChange(nameof(DropsItemName));
}
else
{
DropsItemId = string.Empty;
DropsItemName = string.Empty;
NotifyOfPropertyChange(nameof(DropsItemName));
}
}
///
/// Gets or private sets the list of drops.
///
public ObservableCollection DropsList { get; private set; } = [];
///
/// Gets or sets the item ID of drops.
///
public string DropsItemId
{
get => GetTaskConfig().DropId;
set {
SetTaskConfig(t => t.DropId == value, t => t.DropId = value);
SetFightParams();
}
}
///
/// Gets or sets the item Name of drops.
///
public string DropsItemName { get; set; } = string.Empty;
// UI 绑定的方法
[UsedImplicitly]
public void DropsListDropDownClosed()
{
if (DropsList.FirstOrDefault(i => i.Display == DropsItemName) is { } item)
{
DropsItemId = item.Value;
}
else
{
DropsItemId = string.Empty;
DropsItemName = LocalizationHelper.GetString("NotSelected");
NotifyOfPropertyChange(nameof(DropsItemName));
}
}
///
/// Gets or sets the quantity of drops.
///
public int DropsQuantity
{
get => GetTaskConfig().DropCount;
set {
SetTaskConfig(t => t.DropCount == value, t => t.DropCount = value);
SetFightParams();
}
}
#endregion Drops
public static Dictionary AnnihilationModeList { get; } = new()
{
{ LocalizationHelper.GetString("Annihilation"), "Annihilation" },
{ LocalizationHelper.GetString("Chernobog"), "Chernobog@Annihilation" },
{ LocalizationHelper.GetString("LungmenOutskirts"), "LungmenOutskirts@Annihilation" },
{ LocalizationHelper.GetString("LungmenDowntown"), "LungmenDowntown@Annihilation" },
};
public bool UseCustomAnnihilation
{
get => GetTaskConfig().UseCustomAnnihilation;
set => SetTaskConfig(t => t.UseCustomAnnihilation == value, t => t.UseCustomAnnihilation = value);
}
public string AnnihilationStage
{
get => GetTaskConfig().AnnihilationStage;
set => SetTaskConfig(t => t.AnnihilationStage == value, t => t.AnnihilationStage = value);
}
///
/// Gets or sets a value indicating whether to use DrGrandet mode.
///
public bool IsDrGrandet
{
get => GetTaskConfig().IsDrGrandet;
set => SetTaskConfig(t => t.IsDrGrandet == value, t => t.IsDrGrandet = value);
}
///
/// Gets or sets a value indicating whether to use alternate stage.
///
public bool UseAlternateStage
{
get => GetTaskConfig().UseOptionalStage;
set {
SetTaskConfig(t => t.UseOptionalStage == value, t => t.UseOptionalStage = value);
if (value)
{
HideUnavailableStage = false;
}
else
{
var list = StagePlan;
if (list.Count == 0)
{
var item = new StagePlanItem();
item.PropertyChanged += (_, __) => SaveStagePlan();
StagePlan.Add(item);
}
else
{
var stage = list[0];
StagePlan.Clear();
StagePlan.Add(stage);
}
}
}
}
public bool AllowUseStoneSave
{
get => GetTaskConfig().UseStoneAllowSave;
set {
if (value)
{
var result = MessageBoxHelper.Show(
LocalizationHelper.GetString("AllowUseStoneSaveWarning"),
LocalizationHelper.GetString("Warning"),
MessageBoxButton.YesNo,
MessageBoxImage.Warning,
no: LocalizationHelper.GetString("Confirm"),
yes: LocalizationHelper.GetString("Cancel"),
iconBrushKey: "DangerBrush");
if (result != MessageBoxResult.No)
{
return;
}
}
SetTaskConfig(t => t.UseStoneAllowSave == value, t => t.UseStoneAllowSave = value);
}
}
public bool UseExpiringMedicine
{
get => GetTaskConfig().UseExpiringMedicine;
set {
SetTaskConfig(t => t.UseExpiringMedicine == value, t => t.UseExpiringMedicine = value);
SetFightParams();
}
}
///
/// Gets or sets a value indicating whether to hide unavailable stages.
///
public bool HideUnavailableStage
{
get => GetTaskConfig().HideUnavailableStage;
set {
var update = SetTaskConfig(t => t.HideUnavailableStage == value, t => t.HideUnavailableStage = value);
if (value)
{
UseAlternateStage = false;
}
if (update)
{
UpdateStageList();
}
}
}
///
/// Gets or sets a value indicating whether to hide series.
///
public bool HideSeries
{
get => GetTaskConfig().HideSeries;
set => SetTaskConfig(t => t.HideSeries == value, t => t.HideSeries = value);
}
///
/// Gets or sets a value indicating whether to use weekly schedule.
///
public bool UseWeeklySchedule
{
get => GetTaskConfig().UseWeeklySchedule;
set => SetTaskConfig(t => t.UseWeeklySchedule == value, t => t.UseWeeklySchedule = value);
}
public ObservableCollection WeeklyScheduleSource { get; set; } = new(Enum.GetValues().Select(i => new WeeklyScheduleItem(i)));
private bool _autoRestartOnDrop = ConfigurationHelper.GetValue(ConfigurationKeys.AutoRestartOnDrop, true);
public bool AutoRestartOnDrop
{
get => _autoRestartOnDrop;
set {
SetAndNotify(ref _autoRestartOnDrop, value);
ConfigurationHelper.SetValue(ConfigurationKeys.AutoRestartOnDrop, value.ToString());
}
}
private static string ToUpperAndCheckStage(string value)
{
if (string.IsNullOrEmpty(value))
{
return value;
}
string upperValue = value.ToUpper();
if (_stageDictionary.TryGetValue(upperValue, out var stage))
{
return stage;
}
if (Instance.StageListSource == null)
{
return value;
}
foreach (var item in Instance.StageListSource)
{
if (upperValue.Equals(item.Value, StringComparison.CurrentCultureIgnoreCase) || upperValue.Equals(item.Display, StringComparison.CurrentCultureIgnoreCase))
{
return item.Value;
}
}
return value;
}
public static string? GetFightStage(IEnumerable stageNames)
{
var stage = stageNames.FirstOrDefault(Instances.TaskQueueViewModel.IsStageOpen);
stage ??= stageNames.FirstOrDefault();
return stage;
}
public override void RefreshUI(BaseTask baseTask)
{
if (baseTask is not FightTask fight)
{
return;
}
IsRefreshingUI = true;
if (!UseAlternateStage && fight.StagePlan.Count == 0)
{
fight.StagePlan.Add(string.Empty);
}
InitDrops();
UpdateStageList(); // 临时修复, 应为同步
RefreshCurrentStagePlan();
RefreshWeeklySchedule();
Refresh();
IsRefreshingUI = false;
}
[Obsolete("使用SerializeTask作为代替")]
public override (AsstTaskType Type, JObject Params) Serialize()
{
var task = new AsstFightTask() {
// Stage = Stage,
Medicine = UseMedicine != false ? MedicineNumber : 0,
Stone = UseStoneDisplay ? StoneNumber : 0,
Series = Series,
MaxTimes = HasTimesLimited != false ? MaxTimes : int.MaxValue,
ExpiringMedicine = UseExpiringMedicine ? 9999 : 0,
IsDrGrandet = IsDrGrandet,
ReportToPenguin = SettingsViewModel.GameSettings.EnablePenguin,
ReportToYituliu = SettingsViewModel.GameSettings.EnableYituliu,
PenguinId = SettingsViewModel.GameSettings.PenguinId,
YituliuId = SettingsViewModel.GameSettings.PenguinId,
ServerType = Instances.SettingsViewModel.ServerType,
ClientType = SettingsViewModel.GameSettings.ClientType,
};
if (task.Stage == "Annihilation" && UseCustomAnnihilation)
{
task.Stage = AnnihilationStage;
}
if (IsSpecifiedDrops != false && !string.IsNullOrEmpty(DropsItemId))
{
task.Drops.Add(DropsItemId, DropsQuantity);
}
if (HasTimesLimited is not false && Series > 0 && MaxTimes % Series != 0)
{
Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetStringFormat("FightTimesMayNotExhausted", MaxTimes, Series), UiLogColor.Warning);
}
return task.Serialize();
}
private bool? SetFightParams()
{
if (TaskSettingVisibilityInfo.CurrentTask is not FightTask fight)
{
return null;
}
if (ConfigFactory.CurrentConfig.TaskQueue.IndexOf(fight) is int index && index > -1)
{
return SerializeTask(fight, Instances.TaskQueueViewModel.TaskItemViewModels[index].TaskId);
}
_logger.Error("Failed to set fight params: current task is not in the task queue.");
return null;
}
public override bool? SerializeTask(BaseTask? baseTask, int? taskId = null)
{
if (baseTask is not FightTask fight)
{
return null;
}
if (fight.UseWeeklySchedule && fight.WeeklySchedule.TryGetValue(Instances.TaskQueueViewModel.CurDayOfWeek, out var isEnabled) && !isEnabled)
{
return null;
}
using var scope = _lock.EnterScope();
var stage = GetFightStage(fight.StagePlan);
if (stage is null)
{
return null;
}
var task = new AsstFightTask() {
Stage = stage,
Medicine = fight.UseMedicine != false ? fight.MedicineCount : 0,
Stone = fight.UseStone != false ? fight.StoneCount : 0,
Series = fight.Series,
MaxTimes = fight.EnableTimesLimit != false ? fight.TimesLimit : int.MaxValue,
ExpiringMedicine = fight.UseExpiringMedicine ? 9999 : 0,
IsDrGrandet = fight.IsDrGrandet,
ReportToPenguin = SettingsViewModel.GameSettings.EnablePenguin,
ReportToYituliu = SettingsViewModel.GameSettings.EnableYituliu,
PenguinId = SettingsViewModel.GameSettings.PenguinId,
YituliuId = SettingsViewModel.GameSettings.PenguinId,
ServerType = Instances.SettingsViewModel.ServerType,
ClientType = SettingsViewModel.GameSettings.ClientType,
};
if (task.Stage == "Annihilation" && fight.UseCustomAnnihilation)
{
task.Stage = AnnihilationStage;
}
if (fight.EnableTargetDrop != false && !string.IsNullOrEmpty(fight.DropId))
{
task.Drops.Add(fight.DropId, fight.DropCount);
}
if (fight.EnableTimesLimit is not false && fight.Series > 0 && fight.TimesLimit % fight.Series != 0)
{
Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetStringFormat("FightTimesMayNotExhausted", fight.TimesLimit, fight.Series), UiLogColor.Warning);
}
return taskId switch {
int id when id > 0 => Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task),
null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Fight, task),
_ => null,
};
}
#region 关卡列表更新
///
/// Updates stage list.
/// 使用手动输入时,只更新关卡列表,不更新关卡选择
/// 使用隐藏当日不开放时,更新关卡列表,关卡选择为未开放的关卡时清空
/// 使用备选关卡时,更新关卡列表,关卡选择为未开放的关卡时在关卡列表中添加对应未开放关卡,避免清空导致进入上次关卡
/// 啥都不选时,更新关卡列表,关卡选择为未开放的关卡时在关卡列表中添加对应未开放关卡,避免清空导致进入上次关卡
/// 除手动输入外所有情况下,如果剩余理智为未开放的关卡,会被清空
///
// FIXME: 被注入对象只能在private函数内使用,只有Model显示之后才会被注入。如果Model还没有触发OnInitialActivate时调用函数会NullPointerException
// 这个函数被列为public可见,意味着他注入对象前被调用
public void UpdateStageList()
{
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(listSource);
if (TaskSettingVisibilityInfo.CurrentTask is FightTask current)
{
current.StagePlan = listCurrent;
}
foreach (var task in ConfigFactory.CurrentConfig.TaskQueue.Where(i => i is FightTask).OfType())
{
var removeList = task.StagePlan.Where(i => !stageList.Any(p => p.Value == i)).ToList();
if (removeList.Count != 0)
{
_logger.Information("Removed non-existing stage from plan: {Stage}", removeList);
task.StagePlan = [.. task.StagePlan.Where(i => stageList.Any(p => p.Value == i))];
}
}
RefreshCurrentStagePlan();
});
}
private void RefreshCurrentStagePlan()
{
if (TaskSettingVisibilityInfo.CurrentTask is not FightTask)
{
return;
}
var plan = GetTaskConfig().StagePlan.ToList();
var list = plan.Select((i, index) => new StagePlanItem() { Value = i }).ToList();
foreach (var item in list)
{
item.PropertyChanged += (_, __) => SaveStagePlan();
}
StagePlan = new ObservableCollection(list);
StagePlan.CollectionChanged += (_, __) => SaveStagePlan();
}
private void SaveStagePlan()
{
var list = StagePlan.Select(i => i.Value).ToList();
SetTaskConfig(t => t.StagePlan.SequenceEqual(list), t => t.StagePlan = list);
}
private void RefreshWeeklySchedule()
{
var plan = GetTaskConfig().WeeklySchedule;
foreach (var item in WeeklyScheduleSource)
{
item.Value = !plan.TryGetValue(item.DayOfWeek, out var value) || value;
}
}
private void SaveWeeklySchedule()
{
if (IsRefreshingUI)
{
return;
}
var dict = WeeklyScheduleSource.ToDictionary(i => i.DayOfWeek, i => i.Value);
SetTaskConfig(t => t.WeeklySchedule.SequenceEqual(dict), t => t.WeeklySchedule = dict);
}
#endregion 关卡列表更新
public class SanityInfo
{
[JsonProperty("current_sanity")]
public int SanityCurrent { get; set; }
[JsonProperty("max_sanity")]
public int SanityMax { get; set; }
[JsonProperty("report_time")]
public DateTimeOffset ReportTime { get; set; }
}
public class FightTimes
{
[JsonProperty("sanity_cost")]
public int SanityCost { get; set; }
[JsonProperty("series")]
public int Series { get; set; }
[JsonProperty("times_finished")]
public int TimesFinished { get; set; }
[JsonProperty("finished")]
public bool IsFinished { get; set; }
}
public class WeeklyScheduleItem(DayOfWeek dayOfWeek) : PropertyChangedBase
{
public string Display => LocalizationHelper.CustomCultureInfo.DateTimeFormat.GetDayName(DayOfWeek);
public DayOfWeek DayOfWeek { get; } = dayOfWeek;
public bool Value { get => field; set => SetAndNotify(ref field, value); } = true;
}
public class StageSourceItem : PropertyChangedBase
{
public string Display { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
public bool IsOpen { get => field; set => SetAndNotify(ref field, value); } = true;
public bool IsVisible { get => field; set => SetAndNotify(ref field, value); } = true;
}
public class StagePlanItem : PropertyChangedBase
{
public string Value
{
get => field;
set {
value ??= string.Empty;
if (TaskSettingVisibilityInfo.CurrentTask is FightTask task && task.UseOptionalStage)
{
// 从后往前删
if (value.Length != 3)
{
value = ToUpperAndCheckStage(value);
}
}
if (!SetAndNotify(ref field, value))
{
return;
}
IsOpen = Instances.StageManager.GetStageList().FirstOrDefault(p => p.Value == value)?.IsStageOpen(Instances.TaskQueueViewModel.CurDayOfWeek) ?? true;
}
} = string.Empty;
public bool IsOpen { get => field; set => SetAndNotify(ref field, value); } = true;
}
}