Files
MaaAssistantArknights/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/FightSettingsUserControlModel.cs

929 lines
30 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// <copyright file="FightSettingsUserControlModel.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>
#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;
/// <summary>
/// 理智作战
/// </summary>
public class FightSettingsUserControlModel : TaskSettingsViewModel
{
private static readonly ILogger _logger = Log.ForContext<FightSettingsUserControlModel>();
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; }
/// <summary>
/// Gets or private sets the list of stages.
/// </summary>
public ObservableCollection<StageSourceItem> StageListSource
{
get => field;
private set => SetAndNotify(ref field, value);
} = [];
private static readonly Dictionary<string, string> _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<StagePlanItem> 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);
}
/// <summary>
/// Gets or sets the stage1.
/// </summary>
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();
}
}
/// <summary>
/// Gets or sets a value indicating whether to use custom stage code.
/// </summary>
public bool CustomStageCode
{
get => GetTaskConfig<FightTask>().IsStageManually;
set => SetTaskConfig<FightTask>(t => t.IsStageManually == value, t => t.IsStageManually = value);
}
/// <summary>
/// Reset unsaved battle parameters.
/// </summary>
/// <param name="fight">The fight task.</param>
public static void ResetFightVariables(FightTask? fight)
{
fight?.UseStone ??= false;
fight?.UseMedicine ??= false;
fight?.EnableTimesLimit ??= false;
fight?.EnableTargetDrop ??= false;
}
/// <summary>
/// Gets or sets a value indicating whether to use medicine with null.
/// </summary>
public bool? UseMedicine
{
get => GetTaskConfig<FightTask>().UseMedicine;
set {
if (!SetTaskConfig<FightTask>(t => t.UseMedicine == value, t => t.UseMedicine = value))
{
return;
}
if (value == false)
{
UseStoneDisplay = false;
}
SetFightParams();
}
}
/// <summary>
/// Gets or sets the amount of medicine used.
/// </summary>
public int MedicineNumber
{
get => GetTaskConfig<FightTask>().MedicineCount;
set {
if (!SetTaskConfig<FightTask>(t => t.MedicineCount == value, t => t.MedicineCount = value))
{
return;
}
SetFightParams();
}
}
public static string UseStoneString => LocalizationHelper.GetString("UseOriginitePrime");
/// <summary>
/// Gets or sets a value indicating whether to use originiums with null.
/// </summary>
public bool? UseStone
{
get => GetTaskConfig<FightTask>().UseStone;
set {
if (!AllowUseStoneSave && value == true)
{
value = null;
}
if (value != false)
{
MedicineNumber = 999;
if (UseMedicine == false)
{
UseMedicine = value;
}
}
SetFightParams();
SetTaskConfig<FightTask>(t => t.UseStone == value, t => t.UseStone = value);
}
}
/// <summary>
/// Gets or sets a value indicating whether to use originiums.
/// </summary>
// ReSharper disable once MemberCanBePrivate.Global
[PropertyDependsOn(nameof(UseStone))]
public bool UseStoneDisplay
{
get => UseStone != false;
set => UseStone = value;
}
/// <summary>
/// Gets or sets the amount of originiums used.
/// </summary>
public int StoneNumber
{
get => GetTaskConfig<FightTask>().StoneCount;
set {
if (!SetTaskConfig<FightTask>(t => t.StoneCount == value, t => t.StoneCount = value))
{
return;
}
SetFightParams();
}
}
/// <summary>
/// Gets or sets a value indicating whether the number of times is limited with null.
/// </summary>
public bool? HasTimesLimited
{
get => GetTaskConfig<FightTask>().EnableTimesLimit;
set {
if (!SetTaskConfig<FightTask>(t => t.EnableTimesLimit == value, t => t.EnableTimesLimit = value))
{
return;
}
SetFightParams();
}
}
/// <summary>
/// Gets or sets the max number of times.
/// </summary>
public int MaxTimes
{
get => GetTaskConfig<FightTask>().TimesLimit;
set {
if (!SetTaskConfig<FightTask>(t => t.TimesLimit == value, t => t.TimesLimit = value))
{
return;
}
SetFightParams();
}
}
public static Dictionary<string, int> SeriesList { get; set; } = new()
{
{ "AUTO", 0 },
{ "6", 6 },
{ "5", 5 },
{ "4", 4 },
{ "3", 3 },
{ "2", 2 },
{ "1", 1 },
{ LocalizationHelper.GetString("NotSwitch"), -1 },
};
/// <summary>
/// Gets or sets the max number of times.
/// </summary>
public int Series
{
get => GetTaskConfig<FightTask>().Series;
set {
if (!SetTaskConfig<FightTask>(t => t.Series == value, t => t.Series = value))
{
return;
}
SetFightParams();
}
}
#region Drops
/// <summary>
/// Gets or sets a value indicating whether the drops are specified.
/// </summary>
public bool? IsSpecifiedDrops
{
get => GetTaskConfig<FightTask>().EnableTargetDrop;
set {
if (!SetTaskConfig<FightTask>(t => t.EnableTargetDrop == value, t => t.EnableTargetDrop = value))
{
return;
}
SetFightParams();
}
}
/// <summary>
/// Gets the list of all drops.
/// </summary>
private List<CombinedData> AllDrops { get; } = [];
/// <summary>
/// 关卡不可掉落的材料
/// </summary>
private static readonly HashSet<string> _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));
}
}
/// <summary>
/// Gets or private sets the list of drops.
/// </summary>
public ObservableCollection<CombinedData> DropsList { get; private set; } = [];
/// <summary>
/// Gets or sets the item ID of drops.
/// </summary>
public string DropsItemId
{
get => GetTaskConfig<FightTask>().DropId;
set {
SetTaskConfig<FightTask>(t => t.DropId == value, t => t.DropId = value);
SetFightParams();
}
}
/// <summary>
/// Gets or sets the item Name of drops.
/// </summary>
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));
}
}
/// <summary>
/// Gets or sets the quantity of drops.
/// </summary>
public int DropsQuantity
{
get => GetTaskConfig<FightTask>().DropCount;
set {
SetTaskConfig<FightTask>(t => t.DropCount == value, t => t.DropCount = value);
SetFightParams();
}
}
#endregion Drops
public static Dictionary<string, string> 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<FightTask>().UseCustomAnnihilation;
set => SetTaskConfig<FightTask>(t => t.UseCustomAnnihilation == value, t => t.UseCustomAnnihilation = value);
}
public string AnnihilationStage
{
get => GetTaskConfig<FightTask>().AnnihilationStage;
set => SetTaskConfig<FightTask>(t => t.AnnihilationStage == value, t => t.AnnihilationStage = value);
}
/// <summary>
/// Gets or sets a value indicating whether to use DrGrandet mode.
/// </summary>
public bool IsDrGrandet
{
get => GetTaskConfig<FightTask>().IsDrGrandet;
set => SetTaskConfig<FightTask>(t => t.IsDrGrandet == value, t => t.IsDrGrandet = value);
}
/// <summary>
/// Gets or sets a value indicating whether to use alternate stage.
/// </summary>
public bool UseAlternateStage
{
get => GetTaskConfig<FightTask>().UseOptionalStage;
set {
SetTaskConfig<FightTask>(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<FightTask>().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<FightTask>(t => t.UseStoneAllowSave == value, t => t.UseStoneAllowSave = value);
}
}
public bool UseExpiringMedicine
{
get => GetTaskConfig<FightTask>().UseExpiringMedicine;
set {
SetTaskConfig<FightTask>(t => t.UseExpiringMedicine == value, t => t.UseExpiringMedicine = value);
SetFightParams();
}
}
/// <summary>
/// Gets or sets a value indicating whether to hide unavailable stages.
/// </summary>
public bool HideUnavailableStage
{
get => GetTaskConfig<FightTask>().HideUnavailableStage;
set {
var update = SetTaskConfig<FightTask>(t => t.HideUnavailableStage == value, t => t.HideUnavailableStage = value);
if (value)
{
UseAlternateStage = false;
}
if (update)
{
UpdateStageList();
}
}
}
/// <summary>
/// Gets or sets a value indicating whether to hide series.
/// </summary>
public bool HideSeries
{
get => GetTaskConfig<FightTask>().HideSeries;
set => SetTaskConfig<FightTask>(t => t.HideSeries == value, t => t.HideSeries = value);
}
/// <summary>
/// Gets or sets a value indicating whether to use weekly schedule.
/// </summary>
public bool UseWeeklySchedule
{
get => GetTaskConfig<FightTask>().UseWeeklySchedule;
set => SetTaskConfig<FightTask>(t => t.UseWeeklySchedule == value, t => t.UseWeeklySchedule = value);
}
public ObservableCollection<WeeklyScheduleItem> WeeklyScheduleSource { get; set; } = new(Enum.GetValues<DayOfWeek>().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<string> 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
/// <summary>
/// Updates stage list.
/// 使用手动输入时,只更新关卡列表,不更新关卡选择
/// 使用隐藏当日不开放时,更新关卡列表,关卡选择为未开放的关卡时清空
/// 使用备选关卡时,更新关卡列表,关卡选择为未开放的关卡时在关卡列表中添加对应未开放关卡,避免清空导致进入上次关卡
/// 啥都不选时,更新关卡列表,关卡选择为未开放的关卡时在关卡列表中添加对应未开放关卡,避免清空导致进入上次关卡
/// 除手动输入外所有情况下,如果剩余理智为未开放的关卡,会被清空
/// </summary>
// 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<StageSourceItem>(listSource);
if (TaskSettingVisibilityInfo.CurrentTask is FightTask current)
{
current.StagePlan = listCurrent;
}
foreach (var task in ConfigFactory.CurrentConfig.TaskQueue.Where(i => i is FightTask).OfType<FightTask>())
{
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<FightTask>().StagePlan.ToList();
var list = plan.Select((i, index) => new StagePlanItem() { Value = i }).ToList();
foreach (var item in list)
{
item.PropertyChanged += (_, __) => SaveStagePlan();
}
StagePlan = new ObservableCollection<StagePlanItem>(list);
StagePlan.CollectionChanged += (_, __) => SaveStagePlan();
}
private void SaveStagePlan()
{
var list = StagePlan.Select(i => i.Value).ToList();
SetTaskConfig<FightTask>(t => t.StagePlan.SequenceEqual(list), t => t.StagePlan = list);
}
private void RefreshWeeklySchedule()
{
var plan = GetTaskConfig<FightTask>().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<FightTask>(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;
}
}