//
// 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.Windows;
using JetBrains.Annotations;
using MaaWpfGui.Configuration.Single.MaaTask;
using MaaWpfGui.Constants;
using MaaWpfGui.Helper;
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 Stylet;
namespace MaaWpfGui.ViewModels.UserControl.TaskQueue;
///
/// 理智作战
///
public class FightSettingsUserControlModel : TaskViewModel
{
public static FightTimes? FightReport { get; set; }
public static SanityInfo? SanityReport { get; set; }
static FightSettingsUserControlModel()
{
Instance = new();
}
public static FightSettingsUserControlModel Instance { get; }
private ObservableCollection _stageList = [];
///
/// Gets or private sets the list of stages.
///
public ObservableCollection StageList
{
get => _stageList;
private set => SetAndNotify(ref _stageList, value);
}
private ObservableCollection _remainingSanityStageList = [];
public ObservableCollection RemainingSanityStageList
{
get => _remainingSanityStageList;
private set => SetAndNotify(ref _remainingSanityStageList, value);
}
///
/// Gets the stage.
///
public string Stage
{
get {
Stage1 ??= _stage1Fallback;
if (!UseAlternateStage)
{
return Stage1;
}
if (Instances.TaskQueueViewModel.IsStageOpen(Stage1))
{
return Stage1;
}
if (Instances.TaskQueueViewModel.IsStageOpen(Stage2 ??= string.Empty))
{
return Stage2;
}
if (Instances.TaskQueueViewModel.IsStageOpen(Stage3 ??= string.Empty))
{
return Stage3;
}
return Instances.TaskQueueViewModel.IsStageOpen(Stage4 ??= string.Empty) ? Stage4 : Stage1;
}
}
private 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 string?[] Stages => [Stage1, Stage2, Stage3, Stage4];
// Try to fix: issues#5742. 关卡选择为 null 时的一个补丁,可能是 StageList 改变后,wpf binding 延迟更新的问题。
private string _stage1Fallback = ConfigurationHelper.GetValue(ConfigurationKeys.Stage1, string.Empty) ?? string.Empty;
private string? _stage1 = ConfigurationHelper.GetValue(ConfigurationKeys.Stage1, string.Empty) ?? string.Empty;
///
/// Gets or sets the stage1.
///
public string? Stage1
{
get => _stage1;
set {
if (_stage1 == value)
{
return;
}
if (CustomStageCode)
{
// 从后往前删
if (_stage1?.Length != 3 && value != null)
{
value = ToUpperAndCheckStage(value);
}
}
SetAndNotify(ref _stage1, value);
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.Stage1, value);
Instances.TaskQueueViewModel.UpdateDatePrompt();
}
}
private string? _stage2 = ConfigurationHelper.GetValue(ConfigurationKeys.Stage2, string.Empty) ?? string.Empty;
///
/// Gets or sets the stage2.
///
public string? Stage2
{
get => _stage2;
set {
if (_stage2 == value)
{
return;
}
if (CustomStageCode)
{
if (_stage2?.Length != 3 && value != null)
{
value = ToUpperAndCheckStage(value);
}
}
SetAndNotify(ref _stage2, value);
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.Stage2, value);
Instances.TaskQueueViewModel.UpdateDatePrompt();
}
}
private string? _stage3 = ConfigurationHelper.GetValue(ConfigurationKeys.Stage3, string.Empty) ?? string.Empty;
///
/// Gets or sets the stage3.
///
public string? Stage3
{
get => _stage3;
set {
if (_stage3 == value)
{
return;
}
if (CustomStageCode)
{
if (_stage3?.Length != 3 && value != null)
{
value = ToUpperAndCheckStage(value);
}
}
SetAndNotify(ref _stage3, value);
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.Stage3, value);
Instances.TaskQueueViewModel.UpdateDatePrompt();
}
}
private string? _stage4 = ConfigurationHelper.GetValue(ConfigurationKeys.Stage4, string.Empty) ?? string.Empty;
///
/// Gets or sets the stage4.
///
public string? Stage4
{
get => _stage4;
set {
if (_stage4 == value)
{
return;
}
if (CustomStageCode)
{
if (_stage4?.Length != 3 && value != null)
{
value = ToUpperAndCheckStage(value);
}
}
SetAndNotify(ref _stage4, value);
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.Stage4, value);
Instances.TaskQueueViewModel.UpdateDatePrompt();
}
}
private bool _useRemainingSanityStage = ConfigurationHelper.GetValue(ConfigurationKeys.UseRemainingSanityStage, true);
public bool UseRemainingSanityStage
{
get => _useRemainingSanityStage;
set {
SetAndNotify(ref _useRemainingSanityStage, value);
ConfigurationHelper.SetValue(ConfigurationKeys.UseRemainingSanityStage, value.ToString());
}
}
private bool _customStageCode = ConfigurationHelper.GetValue(ConfigurationKeys.CustomStageCode, false);
///
/// Gets or sets a value indicating whether to use custom stage code.
///
public bool CustomStageCode
{
get => _customStageCode;
set {
if (!value)
{
RemoveNonExistStage();
}
SetAndNotify(ref _customStageCode, value);
ConfigurationHelper.SetValue(ConfigurationKeys.CustomStageCode, value.ToString());
}
}
///
/// 移除不在关卡列表中的关卡,关闭自定义和刷新关卡列表时调用
///
public void RemoveNonExistStage()
{
Stage1 = StageList.FirstOrDefault(x => x.Value == Stage1)?.Value ?? string.Empty;
Stage2 = StageList.FirstOrDefault(x => x.Value == Stage2)?.Value ?? string.Empty;
Stage3 = StageList.FirstOrDefault(x => x.Value == Stage3)?.Value ?? string.Empty;
Stage4 = StageList.FirstOrDefault(x => x.Value == Stage4)?.Value ?? string.Empty;
RemainingSanityStage = RemainingSanityStageList.FirstOrDefault(x => x.Value == RemainingSanityStage)?.Value ?? string.Empty;
}
private string? _remainingSanityStage = ConfigurationHelper.GetValue(ConfigurationKeys.RemainingSanityStage, string.Empty) ?? string.Empty;
public string? RemainingSanityStage
{
get => _remainingSanityStage;
set {
if (_remainingSanityStage == value)
{
return;
}
if (CustomStageCode)
{
if (_remainingSanityStage?.Length != 3 && value != null)
{
value = ToUpperAndCheckStage(value);
}
}
SetAndNotify(ref _remainingSanityStage, value);
TaskQueueViewModel.SetFightRemainingSanityParams();
ConfigurationHelper.SetValue(ConfigurationKeys.RemainingSanityStage, value);
}
}
///
/// Reset unsaved battle parameters.
///
public void ResetFightVariables()
{
UseStone ??= false;
UseMedicine ??= false;
HasTimesLimited ??= false;
IsSpecifiedDrops ??= false;
}
private bool? _useMedicine = ConfigurationHelper.GetValue(ConfigurationKeys.UseMedicine, false);
///
/// Gets or sets a value indicating whether to use medicine with null.
///
public bool? UseMedicine
{
get => _useMedicine;
set {
SetAndNotify(ref _useMedicine, value);
if (value == false)
{
UseStoneDisplay = false;
}
Instances.TaskQueueViewModel.SetFightParams();
value ??= false;
ConfigurationHelper.SetValue(ConfigurationKeys.UseMedicine, value.ToString());
}
}
private int _medicineNumber = ConfigurationHelper.GetValue(ConfigurationKeys.UseMedicineQuantity, 999);
///
/// Gets or sets the amount of medicine used.
///
public int MedicineNumber
{
get => _medicineNumber;
set {
if (!SetAndNotify(ref _medicineNumber, value))
{
return;
}
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.UseMedicineQuantity, value.ToString());
}
}
public static string UseStoneString => LocalizationHelper.GetString("UseOriginitePrime");
private bool? _useStone = ConfigurationHelper.GetValue(ConfigurationKeys.UseMedicine, false) &&
ConfigurationHelper.GetValue(ConfigurationKeys.UseStone, false);
///
/// Gets or sets a value indicating whether to use originiums with null.
///
public bool? UseStone
{
get => _useStone;
set {
if (!AllowUseStoneSave && value == true)
{
value = null;
}
SetAndNotify(ref _useStone, value);
if (value != false)
{
MedicineNumber = 999;
if (UseMedicine == false)
{
UseMedicine = value;
}
}
Instances.TaskQueueViewModel.SetFightParams();
if (AllowUseStoneSave)
{
ConfigurationHelper.SetValue(ConfigurationKeys.UseStone, (value ?? false).ToString());
}
}
}
///
/// 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;
}
private int _stoneNumber = ConfigurationHelper.GetValue(ConfigurationKeys.UseStoneQuantity, 0);
///
/// Gets or sets the amount of originiums used.
///
public int StoneNumber
{
get => _stoneNumber;
set {
if (!SetAndNotify(ref _stoneNumber, value))
{
return;
}
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.UseStoneQuantity, value.ToString());
}
}
private bool? _hasTimesLimited = ConfigurationHelper.GetValue(ConfigurationKeys.TimesLimited, false);
///
/// Gets or sets a value indicating whether the number of times is limited with null.
///
public bool? HasTimesLimited
{
get => _hasTimesLimited;
set {
SetAndNotify(ref _hasTimesLimited, value);
Instances.TaskQueueViewModel.SetFightParams();
value ??= false;
ConfigurationHelper.SetValue(ConfigurationKeys.TimesLimited, value.ToString());
}
}
private int _maxTimes = ConfigurationHelper.GetValue(ConfigurationKeys.TimesLimitedQuantity, 5);
///
/// Gets or sets the max number of times.
///
public int MaxTimes
{
get => _maxTimes;
set {
if (!SetAndNotify(ref _maxTimes, value))
{
return;
}
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.TimesLimitedQuantity, value.ToString());
}
}
public static Dictionary SeriesList { get; } = new()
{
{ "AUTO", 0 },
{ "6", 6 },
{ "5", 5 },
{ "4", 4 },
{ "3", 3 },
{ "2", 2 },
{ "1", 1 },
{ LocalizationHelper.GetString("NotSwitch"), -1 },
};
private int _series = InitFightSeries();
private static int InitFightSeries()
{
var series = ConfigurationHelper.GetValue(ConfigurationKeys.SeriesQuantity, 0);
if (SeriesList.ContainsValue(series))
{
return series;
}
ConfigurationHelper.SetValue(ConfigurationKeys.SeriesQuantity, "0");
return 0;
}
///
/// Gets or sets the max number of times.
///
public int Series
{
get => _series;
set {
if (!SetAndNotify(ref _series, value))
{
return;
}
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.SeriesQuantity, value.ToString());
}
}
#region Drops
private bool? _isSpecifiedDrops = ConfigurationHelper.GetValue(ConfigurationKeys.DropsEnable, false);
///
/// Gets or sets a value indicating whether the drops are specified.
///
public bool? IsSpecifiedDrops
{
get => _isSpecifiedDrops;
set {
if (!SetAndNotify(ref _isSpecifiedDrops, value))
{
return;
}
Instances.TaskQueueViewModel.SetFightParams();
value ??= false;
ConfigurationHelper.SetValue(ConfigurationKeys.DropsEnable, value.ToString());
}
}
///
/// 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", // 重相位对映体
];
public 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; } = [];
private string _dropsItemId = ConfigurationHelper.GetValue(ConfigurationKeys.DropsItemId, string.Empty) ?? string.Empty;
///
/// Gets or sets the item ID of drops.
///
public string DropsItemId
{
get => _dropsItemId;
set {
SetAndNotify(ref _dropsItemId, value);
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.DropsItemId, DropsItemId);
}
}
///
/// 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));
}
}
private int _dropsQuantity = ConfigurationHelper.GetValue(ConfigurationKeys.DropsQuantity, 5);
///
/// Gets or sets the quantity of drops.
///
public int DropsQuantity
{
get => _dropsQuantity;
set {
SetAndNotify(ref _dropsQuantity, value);
Instances.TaskQueueViewModel.SetFightParams();
ConfigurationHelper.SetValue(ConfigurationKeys.DropsQuantity, value.ToString());
}
}
#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" },
};
private bool _useCustomAnnihilation = ConfigurationHelper.GetValue(ConfigurationKeys.UseCustomAnnihilation, false);
public bool UseCustomAnnihilation
{
get => _useCustomAnnihilation;
set {
SetAndNotify(ref _useCustomAnnihilation, value);
ConfigurationHelper.SetValue(ConfigurationKeys.UseCustomAnnihilation, value.ToString());
}
}
private string _annihilationStage = ConfigurationHelper.GetValue(ConfigurationKeys.AnnihilationStage, "Annihilation");
public string AnnihilationStage
{
get => _annihilationStage;
set {
SetAndNotify(ref _annihilationStage, value);
ConfigurationHelper.SetValue(ConfigurationKeys.AnnihilationStage, value);
}
}
private bool _isDrGrandet = ConfigurationHelper.GetValue(ConfigurationKeys.IsDrGrandet, false);
///
/// Gets or sets a value indicating whether to use DrGrandet mode.
///
public bool IsDrGrandet
{
get => _isDrGrandet;
set {
SetAndNotify(ref _isDrGrandet, value);
ConfigurationHelper.SetValue(ConfigurationKeys.IsDrGrandet, value.ToString());
}
}
private bool _useAlternateStage = ConfigurationHelper.GetValue(ConfigurationKeys.UseAlternateStage, false);
///
/// Gets or sets a value indicating whether to use alternate stage.
///
public bool UseAlternateStage
{
get => _useAlternateStage;
set {
SetAndNotify(ref _useAlternateStage, value);
ConfigurationHelper.SetValue(ConfigurationKeys.UseAlternateStage, value.ToString());
if (value)
{
HideUnavailableStage = false;
}
}
}
private bool _allowUseStoneSave = ConfigurationHelper.GetValue(ConfigurationKeys.AllowUseStoneSave, false);
public bool AllowUseStoneSave
{
get => _allowUseStoneSave;
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;
}
}
SetAndNotify(ref _allowUseStoneSave, value);
ConfigurationHelper.SetValue(ConfigurationKeys.AllowUseStoneSave, value.ToString());
}
}
private bool _useExpiringMedicine = ConfigurationHelper.GetValue(ConfigurationKeys.UseExpiringMedicine, false);
public bool UseExpiringMedicine
{
get => _useExpiringMedicine;
set {
SetAndNotify(ref _useExpiringMedicine, value);
ConfigurationHelper.SetValue(ConfigurationKeys.UseExpiringMedicine, value.ToString());
Instances.TaskQueueViewModel.SetFightParams();
}
}
private bool _hideUnavailableStage = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.HideUnavailableStage, bool.TrueString));
///
/// Gets or sets a value indicating whether to hide unavailable stages.
///
public bool HideUnavailableStage
{
get => _hideUnavailableStage;
set {
SetAndNotify(ref _hideUnavailableStage, value);
ConfigurationHelper.SetValue(ConfigurationKeys.HideUnavailableStage, value.ToString());
if (value)
{
UseAlternateStage = false;
}
UpdateStageList();
}
}
private bool _hideSeries = ConfigurationHelper.GetValue(ConfigurationKeys.HideSeries, false);
///
/// Gets or sets a value indicating whether to hide series.
///
public bool HideSeries
{
get => _hideSeries;
set {
SetAndNotify(ref _hideSeries, value);
ConfigurationHelper.SetValue(ConfigurationKeys.HideSeries, value.ToString());
}
}
private bool _autoRestartOnDrop = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.AutoRestartOnDrop, bool.TrueString));
public bool AutoRestartOnDrop
{
get => _autoRestartOnDrop;
set {
SetAndNotify(ref _autoRestartOnDrop, value);
ConfigurationHelper.SetValue(ConfigurationKeys.AutoRestartOnDrop, value.ToString());
}
}
private string ToUpperAndCheckStage(string value)
{
if (string.IsNullOrEmpty(value))
{
return value;
}
string upperValue = value.ToUpper();
if (_stageDictionary.TryGetValue(upperValue, out var stage))
{
return stage;
}
if (StageList == null)
{
return value;
}
foreach (var item in StageList)
{
if (upperValue == item.Value.ToUpper() || upperValue == item.Display.ToUpper())
{
return item.Value;
}
}
return value;
}
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 (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();
}
#region 双入口设置可见性
private bool _customInfrastPlanShowInFightSettings = ConfigurationHelper.GetValue(ConfigurationKeys.CustomInfrastPlanShowInFightSettings, false);
public bool CustomInfrastPlanShowInFightSettings
{
get => _customInfrastPlanShowInFightSettings;
set {
SetAndNotify(ref _customInfrastPlanShowInFightSettings, value);
ConfigurationHelper.SetValue(ConfigurationKeys.CustomInfrastPlanShowInFightSettings, value.ToString());
}
}
#endregion
#region 关卡列表更新
///
/// Updates stage list.
/// 使用手动输入时,只更新关卡列表,不更新关卡选择
/// 使用隐藏当日不开放时,更新关卡列表,关卡选择为未开放的关卡时清空
/// 使用备选关卡时,更新关卡列表,关卡选择为未开放的关卡时在关卡列表中添加对应未开放关卡,避免清空导致进入上次关卡
/// 啥都不选时,更新关卡列表,关卡选择为未开放的关卡时在关卡列表中添加对应未开放关卡,避免清空导致进入上次关卡
/// 除手动输入外所有情况下,如果剩余理智为未开放的关卡,会被清空
///
// FIXME: 被注入对象只能在private函数内使用,只有Model显示之后才会被注入。如果Model还没有触发OnInitialActivate时调用函数会NullPointerException
// 这个函数被列为public可见,意味着他注入对象前被调用
public void UpdateStageList()
{
Execute.PostToUIThreadAsync(() => {
var hideUnavailableStage = HideUnavailableStage;
Instances.TaskQueueViewModel.EnableSetFightParams = false;
var stage1 = Stage1 ?? string.Empty;
var stage2 = Stage2 ?? string.Empty;
var stage3 = Stage3 ?? string.Empty;
var stage4 = Stage4 ?? string.Empty;
var rss = RemainingSanityStage ?? string.Empty;
var tempStageList = hideUnavailableStage
? Instances.StageManager.GetStageList(Instances.TaskQueueViewModel.CurDayOfWeek).ToList()
: Instances.StageManager.GetStageList().ToList();
var tempRemainingSanityStageList = Instances.StageManager.GetStageList().ToList();
if (CustomStageCode)
{
// 7%
// 使用自定义的时候不做处理
}
else if (hideUnavailableStage)
{
// 15%
stage1 = Instances.TaskQueueViewModel.GetValidStage(stage1);
stage2 = Instances.TaskQueueViewModel.GetValidStage(stage2);
stage3 = Instances.TaskQueueViewModel.GetValidStage(stage3);
stage4 = Instances.TaskQueueViewModel.GetValidStage(stage4);
}
else if (UseAlternateStage)
{
// 11%
AddStagesIfNotExist([stage1, stage2, stage3, stage4], tempStageList);
}
else
{
// 啥都没选
AddStageIfNotExist(stage1, tempStageList);
// 避免关闭了使用备用关卡后,始终添加备用关卡中的未开放关卡
stage2 = Instances.TaskQueueViewModel.GetValidStage(stage2);
stage3 = Instances.TaskQueueViewModel.GetValidStage(stage3);
stage4 = Instances.TaskQueueViewModel.GetValidStage(stage4);
}
// rss 如果结束后还选择了不开放的关卡,理智作战任务会报错
rss = Instances.TaskQueueViewModel.IsStageOpen(rss) ? rss : string.Empty;
if (tempRemainingSanityStageList.Any(item => item.Value == string.Empty))
{
var itemToRemove = tempRemainingSanityStageList.First(item => item.Value == string.Empty);
tempRemainingSanityStageList.Remove(itemToRemove);
}
tempRemainingSanityStageList.Insert(0, new CombinedData { Display = LocalizationHelper.GetString("NoUse"), Value = string.Empty });
UpdateObservableCollection(StageList, tempStageList);
UpdateObservableCollection(RemainingSanityStageList, tempRemainingSanityStageList);
_stage1Fallback = stage1;
Stage1 = stage1;
Stage2 = stage2;
Stage3 = stage3;
Stage4 = stage4;
RemainingSanityStage = rss;
if (!CustomStageCode)
{
RemoveNonExistStage();
}
Instances.TaskQueueViewModel.EnableSetFightParams = true;
});
}
private void AddStagesIfNotExist(IEnumerable stages, List stageList)
{
foreach (var stage in stages)
{
AddStageIfNotExist(stage, stageList);
}
}
private void AddStageIfNotExist(string stage, List stageList)
{
if (stageList.Any(x => x.Value == stage))
{
return;
}
var stageInfo = Instances.StageManager.GetStageInfo(stage);
stageList.Add(stageInfo);
}
///
/// 更新 ObservableCollection,确保不替换原集合,而是增删项
///
/// 原始 ObservableCollection
/// 新的列表
public static void UpdateObservableCollection(ObservableCollection originalCollection, List newList)
{
originalCollection.Clear();
foreach (var item in newList)
{
originalCollection.Add(item);
}
}
#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; }
}
}