// // 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.IO; using System.Linq; using MaaWpfGui.Configuration.Single.MaaTask; using MaaWpfGui.Constants; using MaaWpfGui.Constants.Enums; using MaaWpfGui.Helper; using MaaWpfGui.Main; 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 static MaaWpfGui.Main.AsstProxy; using Mode = MaaWpfGui.Configuration.Single.MaaTask.RoguelikeMode; using RoguelikeBoskySubNodeType = MaaWpfGui.Configuration.Single.MaaTask.RoguelikeBoskySubNodeType; using Theme = MaaWpfGui.Configuration.Single.MaaTask.RoguelikeTheme; namespace MaaWpfGui.ViewModels.UserControl.TaskQueue; public class RoguelikeSettingsUserControlModel : TaskSettingsViewModel { static RoguelikeSettingsUserControlModel() { Instance = new(); } public static RoguelikeSettingsUserControlModel Instance { get; } public void InitRoguelike() { GenerateRoguelikeThemeList(); UpdateRoguelikeParams(); } private void UpdateRoguelikeParams() { // 确保在更新列表之前先更新相关属性 UpdateRoguelikeDifficultyList(); UpdateRoguelikeModeList(); UpdateRoguelikeRolesList(); UpdateRoguelikeSquadList(); UpdateRoguelikeStartWithAllDict(); UpdateRoguelikeCoreCharList(); } private void GenerateRoguelikeThemeList() { RoguelikeThemeList.Add(new() { Display = LocalizationHelper.GetString("RoguelikeThemePhantom"), Value = Theme.Phantom }); RoguelikeThemeList.Add(new() { Display = LocalizationHelper.GetString("RoguelikeThemeMizuki"), Value = Theme.Mizuki }); RoguelikeThemeList.Add(new() { Display = LocalizationHelper.GetString("RoguelikeThemeSami"), Value = Theme.Sami }); RoguelikeThemeList.Add(new() { Display = LocalizationHelper.GetString("RoguelikeThemeSarkaz"), Value = Theme.Sarkaz }); if (SettingsViewModel.GameSettings.ClientType is not "txwy") { // 外服暂未开放界园 RoguelikeThemeList.Add(new() { Display = LocalizationHelper.GetString("RoguelikeThemeJieGarden"), Value = Theme.JieGarden }); } } private void UpdateRoguelikeDifficultyList() { int maxThemeDifficulty = GetMaxDifficultyForTheme(RoguelikeTheme); var difficulty = RoguelikeDifficulty; // 0 = min, -1 = current, int.MaxValue = max var list = Enumerable.Range(0, maxThemeDifficulty + 1).OrderDescending().ToList(); list.Insert(0, -1); list.Insert(1, int.MaxValue); RoguelikeDifficultyList.Clear(); foreach (var i in list) { int value = i; var display = value switch { -1 => LocalizationHelper.GetString("NotSwitch") + " (-1)", int.MaxValue => $"MAX ({maxThemeDifficulty})", 0 => "MIN (0)", _ => value.ToString(), }; RoguelikeDifficultyList.Add(new() { Display = display, Value = value }); } // 验证当前选中的难度是否在新列表中 RoguelikeDifficulty = RoguelikeDifficultyList.Any(item => item.Value == RoguelikeDifficulty) ? difficulty : -1; } private static int GetMaxDifficultyForTheme(Theme theme) => theme switch { Theme.Phantom => 15, Theme.Mizuki => 18, Theme.Sami => 15, Theme.Sarkaz => 18, Theme.JieGarden => 15, _ => 20, }; private void UpdateRoguelikeModeList() { var roguelikeMode = RoguelikeMode; switch (RoguelikeTheme) { case Theme.JieGarden: RoguelikeModeList = [ new() { Display = LocalizationHelper.GetString("RoguelikeStrategyExp"), Value = Mode.Exp }, new() { Display = LocalizationHelper.GetString("RoguelikeStrategyGold"), Value = Mode.Investment }, new() { Display = LocalizationHelper.GetString("RoguelikeStrategyLastReward"), Value = Mode.Collectible }, new() { Display = LocalizationHelper.GetString("RoguelikeStrategyFindPlaytime"), Value = Mode.FindPlaytime }, ]; break; default: RoguelikeModeList = [ new() { Display = LocalizationHelper.GetString("RoguelikeStrategyExp"), Value = Mode.Exp }, new() { Display = LocalizationHelper.GetString("RoguelikeStrategyGold"), Value = Mode.Investment }, new() { Display = LocalizationHelper.GetString("RoguelikeStrategyLastReward"), Value = Mode.Collectible }, new() { Display = LocalizationHelper.GetString("RoguelikeStrategyMonthlySquad"), Value = Mode.Squad }, new() { Display = LocalizationHelper.GetString("RoguelikeStrategyDeepExploration"), Value = Mode.Exploration }, ]; if (RoguelikeTheme == Theme.Sami) { RoguelikeModeList.Add(new() { Display = LocalizationHelper.GetString("RoguelikeStrategyCollapse"), Value = Mode.CLP_PDS }); } break; } RoguelikeMode = RoguelikeModeList.Any(x => x.Value == roguelikeMode) ? roguelikeMode : RoguelikeModeList.First().Value; } private void UpdateRoguelikeRolesList() { var roguelikeRoles = RoguelikeRoles; RoguelikeRolesList = [ new() { Display = LocalizationHelper.GetString("FirstMoveAdvantage"), Value = "先手必胜" }, new() { Display = LocalizationHelper.GetString("SlowAndSteadyWinsTheRace"), Value = "稳扎稳打" }, new() { Display = LocalizationHelper.GetString("OvercomingYourWeaknesses"), Value = "取长补短" }, ]; switch (RoguelikeTheme) { case Theme.JieGarden: RoguelikeRolesList.Add(new() { Display = LocalizationHelper.GetString("FlexibleDeployment"), Value = "灵活部署" }); RoguelikeRolesList.Add(new() { Display = LocalizationHelper.GetString("Unbreakable"), Value = "坚不可摧" }); break; } RoguelikeRolesList.Add(new() { Display = LocalizationHelper.GetString("AsYourHeartDesires"), Value = "随心所欲" }); RoguelikeRoles = RoguelikeRolesList.Any(x => x.Value == roguelikeRoles) ? roguelikeRoles : "稳扎稳打"; } private readonly Dictionary> _squadDictionary = new() { ["Phantom_Default"] = [ ("GatheringSquad", "集群分队"), ("SpearheadSquad", "矛头分队"), ("ResearchSquad", "研究分队"), ], ["Mizuki_Default"] = [ ("GatheringSquad", "集群分队"), ("SpearheadSquad", "矛头分队"), ("IS2NewSquad1", "心胜于物分队"), ("IS2NewSquad2", "物尽其用分队"), ("IS2NewSquad3", "以人为本分队"), ("ResearchSquad", "研究分队"), ], ["Sami_Default"] = [ ("GatheringSquad", "集群分队"), ("SpearheadSquad", "矛头分队"), ("IS3NewSquad1", "永恒狩猎分队"), ("IS3NewSquad2", "生活至上分队"), ("IS3NewSquad3", "科学主义分队"), ("IS3NewSquad4", "特训分队"), ], ["Sarkaz_1"] = [ ("GatheringSquad", "集群分队"), ("SpearheadSquad", "矛头分队"), ("IS4NewSquad2", "博闻广记分队"), ("IS4NewSquad3", "蓝图测绘分队"), ("IS4NewSquad6", "点刺成锭分队"), ("IS4NewSquad7", "拟态学者分队"), ], ["Sarkaz_Default"] = [ ("GatheringSquad", "集群分队"), ("SpearheadSquad", "矛头分队"), ("IS4NewSquad1", "魂灵护送分队"), ("IS4NewSquad2", "博闻广记分队"), ("IS4NewSquad3", "蓝图测绘分队"), ("IS4NewSquad4", "因地制宜分队"), ("IS4NewSquad5", "异想天开分队"), ("IS4NewSquad6", "点刺成锭分队"), ("IS4NewSquad7", "拟态学者分队"), ("IS4NewSquad8", "专业人士分队"), ], ["JieGarden_Default"] = [ ("SpecialForceSquad", "特勤分队"), ("IS5NewSquad1", "高台突破分队"), ("IS5NewSquad2", "地面突破分队"), ("IS5NewSquad3", "游客分队"), ("IS5NewSquad4", "司岁台分队"), ("IS5NewSquad5", "天师府分队"), ("IS5NewSquad6", "花团锦簇分队"), ("IS5NewSquad7", "棋行险着分队"), ("IS5NewSquad8", "岁影回音分队"), ("IS5NewSquad9", "代理人分队"), ("IS5NewSquad10", "知学分队"), ("IS5NewSquad11", "商贾分队"), ], }; // 通用分队 private readonly List<(string Key, string Value)> _commonSquads = [ ("LeaderSquad", "指挥分队"), ("SupportSquad", "后勤分队"), ("TacticalAssaultOperative", "突击战术分队"), ("TacticalFortificationOperative", "堡垒战术分队"), ("TacticalRangedOperative", "远程战术分队"), ("TacticalDestructionOperative", "破坏战术分队"), ("First-ClassSquad", "高规格分队"), ]; private void UpdateRoguelikeSquadList() { var roguelikeSquad = RoguelikeSquad; RoguelikeSquadList = []; // 优先匹配 Theme_Mode,其次匹配 Theme_Default string themeKey = $"{RoguelikeTheme}_{RoguelikeMode}"; if (!_squadDictionary.ContainsKey(themeKey)) { themeKey = $"{RoguelikeTheme}_Default"; } // 添加主题分队 if (_squadDictionary.TryGetValue(themeKey, out var squads)) { foreach (var (key, value) in squads) { RoguelikeSquadList.Add(new() { Display = LocalizationHelper.GetString(key), Value = value }); } } // 添加通用分队 foreach (var (key, value) in _commonSquads) { RoguelikeSquadList.Add(new() { Display = LocalizationHelper.GetString(key), Value = value }); } // 选择当前分队 RoguelikeSquad = RoguelikeSquadList.Any(x => x.Value == roguelikeSquad) ? roguelikeSquad : "指挥分队"; RoguelikeCollectibleModeSquad = RoguelikeSquadList.Any(x => x.Value == RoguelikeCollectibleModeSquad) ? RoguelikeCollectibleModeSquad : RoguelikeSquad; } private void UpdateRoguelikeCoreCharList() { var filePath = $"resource/roguelike/{RoguelikeTheme}/recruitment.json"; if (!File.Exists(filePath)) { RoguelikeCoreCharList.Clear(); return; } var jsonStr = File.ReadAllText(filePath); var json = (JObject?)JsonConvert.DeserializeObject(jsonStr); var roguelikeCoreCharList = new ObservableCollection(); if (json?["priority"] is JArray priorityArray) { foreach (var priorityItem in priorityArray) { if (priorityItem?["opers"] is not JArray opersArray) { continue; } foreach (var operItem in opersArray) { var isStart = (bool?)operItem["is_start"] ?? false; if (!isStart) { continue; } var name = (string?)operItem["name"]; if (string.IsNullOrEmpty(name)) { continue; } if (!DataHelper.IsCharacterAvailableInClient(name, SettingsViewModel.GameSettings.ClientType)) { continue; } var localizedName = DataHelper.GetLocalizedCharacterName(name, SettingsViewModel.GuiSettings.OperNameLocalization); if (!string.IsNullOrEmpty(localizedName)) { roguelikeCoreCharList.Add(localizedName); } } } } RoguelikeCoreCharList = roguelikeCoreCharList; } private ObservableCollection> _roguelikeDifficultyList = []; public ObservableCollection> RoguelikeDifficultyList { get => _roguelikeDifficultyList; set => SetAndNotify(ref _roguelikeDifficultyList, value); } private ObservableCollection> _roguelikeModeList = []; /// /// Gets or sets the list of roguelike modes. /// public ObservableCollection> RoguelikeModeList { get => _roguelikeModeList; set => SetAndNotify(ref _roguelikeModeList, value); } private ObservableCollection _roguelikeSquadList = []; /// /// Gets or sets the list of roguelike squad. /// public ObservableCollection RoguelikeSquadList { get => _roguelikeSquadList; set => SetAndNotify(ref _roguelikeSquadList, value); } private ObservableCollection _roguelikeRolesList = []; /// /// Gets or sets the list of roguelike roles. /// public ObservableCollection RoguelikeRolesList { get => _roguelikeRolesList; set => SetAndNotify(ref _roguelikeRolesList, value); } /// /// Gets the list of roguelike lists. /// public List> RoguelikeThemeList { get; } = []; /// /// Gets or sets the Roguelike theme. /// public Theme RoguelikeTheme { get => GetTaskConfig().Theme; set { SetTaskConfig(t => t.Theme == value, t => t.Theme = value); // Check and adjust difficulty if current value is not supported by new theme int maxDifficulty = GetMaxDifficultyForTheme(value); if (RoguelikeDifficulty != -1 && RoguelikeDifficulty != int.MaxValue && RoguelikeDifficulty > maxDifficulty) { RoguelikeDifficulty = -1; // Set to "Current" if not supported } UpdateRoguelikeParams(); // 强制刷新难度显示 OnPropertyChanged(nameof(RoguelikeDifficulty)); // 更新主题提示 OnPropertyChanged(nameof(RoguelikeThemeTip)); } } public int RoguelikeDifficulty { get => GetTaskConfig().Difficulty; set => SetTaskConfig(t => t.Difficulty == value, t => t.Difficulty = value); } /// /// Gets or sets 策略,往后打 / 刷一层就退 / 烧热水 /// public Mode RoguelikeMode { get => GetTaskConfig().Mode; set { if (value == Mode.Investment) { RoguelikeInvestmentEnabled = true; } SetTaskConfig(t => t.Mode == value, t => t.Mode = value); UpdateRoguelikeSquadList(); } } /// /// Gets or sets the roguelike squad. /// public string RoguelikeSquad { get => GetTaskConfig().Squad; set => SetTaskConfig(t => t.Squad == value, t => t.Squad = value); } /// /// Gets or sets the roguelike squad using for last reward mode. /// public string RoguelikeCollectibleModeSquad { get => GetTaskConfig().SquadCollectible; set => SetTaskConfig(t => t.SquadCollectible == value, t => t.SquadCollectible = value); } [PropertyDependsOn(nameof(RoguelikeMode), nameof(RoguelikeTheme), nameof(RoguelikeSquad))] public bool RoguelikeSquadIsProfessional => RoguelikeMode == Mode.Collectible && RoguelikeTheme != Theme.Phantom && RoguelikeSquad is "突击战术分队" or "堡垒战术分队" or "远程战术分队" or "破坏战术分队"; [PropertyDependsOn(nameof(RoguelikeMode), nameof(RoguelikeTheme), nameof(RoguelikeSquad))] public bool RoguelikeSquadIsFoldartal => RoguelikeMode == Mode.Collectible && RoguelikeTheme == Theme.Sami && RoguelikeSquad == "生活至上分队"; /// /// Gets or sets the roguelike roles. /// public string RoguelikeRoles { get => GetTaskConfig().Roles; set => SetTaskConfig(t => t.Roles == value, t => t.Roles = value); } /// /// Gets or sets the roguelike core character. /// public string RoguelikeCoreChar { get => GetTaskConfig().CoreChar; set { if (!SetTaskConfig(t => t.CoreChar == value, t => t.CoreChar = value)) { return; } Instances.TaskQueueViewModel.AddLog("Core Char:" + value); } } private ObservableCollection _roguelikeCoreCharList = []; /// /// Gets the roguelike core character. /// public ObservableCollection RoguelikeCoreCharList { get => _roguelikeCoreCharList; private set { if (!string.IsNullOrEmpty(RoguelikeCoreChar) && !value.Contains(RoguelikeCoreChar)) { value.Add(RoguelikeCoreChar); } SetAndNotify(ref _roguelikeCoreCharList, value); } } /// /// Gets or sets a value indicating whether core char need start with elite two. /// public bool RoguelikeStartWithEliteTwo { get => GetTaskConfig().StartWithEliteTwo; set { switch (value) { case true when RoguelikeUseSupportUnit: RoguelikeUseSupportUnit = false; break; case false when RoguelikeOnlyStartWithEliteTwoRaw: RoguelikeOnlyStartWithEliteTwoRaw = false; break; } SetTaskConfig(t => t.StartWithEliteTwo == value, t => t.StartWithEliteTwo = value); } } /// /// Gets or sets a value indicating whether only need with elite two's core char. /// public bool RoguelikeOnlyStartWithEliteTwoRaw { get => GetTaskConfig().StartWithEliteTwoOnly; set => SetTaskConfig(t => t.StartWithEliteTwoOnly == value, t => t.StartWithEliteTwoOnly = value); } /// /// Gets a value indicating whether only need with elite two's core char. /// [PropertyDependsOn(nameof(RoguelikeOnlyStartWithEliteTwoRaw), nameof(RoguelikeStartWithEliteTwo), nameof(RoguelikeSquadIsProfessional))] public bool RoguelikeOnlyStartWithEliteTwo => RoguelikeOnlyStartWithEliteTwoRaw && RoguelikeStartWithEliteTwo && RoguelikeSquadIsProfessional; /// /// Gets the available start with rewards dictionary based on current theme. /// public List> RoguelikeStartAwards { get; private set; } = []; /// /// Gets a tip text for current Roguelike theme. /// public string RoguelikeThemeTip { get { var key = RoguelikeTheme switch { Theme.Phantom => "RoguelikeThemeTipPhantom", Theme.Mizuki => "RoguelikeThemeTipMizuki", Theme.Sami => "RoguelikeThemeTipSami", Theme.Sarkaz => "RoguelikeThemeTipSarkaz", Theme.JieGarden => "RoguelikeThemeTipJieGarden", _ => "RoguelikeThemeTipPhantom", }; var tip = LocalizationHelper.GetString(key); return string.IsNullOrWhiteSpace(tip) ? LocalizationHelper.GetString("RoguelikeTheme") ?? string.Empty : tip; } } private void UpdateRoguelikeStartWithAllDict() { var config = GetTaskConfig().CollectibleStartAwards; var list = new List>() { new() { Display = LocalizationHelper.GetString("RoguelikeStartWithKettle"), Value = RoguelikeCollectibleAward.HotWater }, new() { Display = LocalizationHelper.GetString("RoguelikeStartWithShield"), Value = RoguelikeCollectibleAward.Shield }, new() { Display = LocalizationHelper.GetString("RoguelikeStartWithIngot"), Value = RoguelikeCollectibleAward.Ingot }, new() { Display = LocalizationHelper.GetString("RoguelikeStartWithHope"), Value = RoguelikeCollectibleAward.Hope }, new() { Display = LocalizationHelper.GetString("RoguelikeStartWithRandomReward"), Value = RoguelikeCollectibleAward.Random }, }; switch (RoguelikeTheme) { case Theme.Mizuki: list.Add(new() { Display = LocalizationHelper.GetString("RoguelikeStartWithKey"), Value = RoguelikeCollectibleAward.Key }); list.Add(new() { Display = LocalizationHelper.GetString("RoguelikeStartWithDice"), Value = RoguelikeCollectibleAward.Dice }); break; case Theme.Sarkaz: list.Add(new() { Display = LocalizationHelper.GetString("RoguelikeStartWithIdea"), Value = RoguelikeCollectibleAward.Idea }); break; case Theme.JieGarden: list.Remove(list.First(i => i.Value == RoguelikeCollectibleAward.Hope)); list.Add(new() { Display = LocalizationHelper.GetString("RoguelikeStartWithTicket"), Value = RoguelikeCollectibleAward.Ticket }); break; } RoguelikeStartAwards = list; OnPropertyChanged(nameof(RoguelikeStartAwards)); RoguelikeStartWithSelectList = RoguelikeStartAwards.Where(i => config.HasFlag(i.Value)).ToArray(); } public object[] RoguelikeStartWithSelectList { get { var value = GetTaskConfig().CollectibleStartAwards; return RoguelikeStartAwards.Where(v => value.HasFlag(v.Value)).ToArray(); } set { var v = value.Cast>().Select(k => k.Value).DefaultIfEmpty((RoguelikeCollectibleAward)0).Aggregate((a, b) => a | b); SetTaskConfig(t => t.CollectibleStartAwards == v, t => t.CollectibleStartAwards = v); } } /// /// Gets or sets a value indicating whether core char need start with elite two. /// public bool Roguelike3FirstFloorFoldartal { get => GetTaskConfig().SamiFirstFloorFoldartal; set => SetTaskConfig(t => t.SamiFirstFloorFoldartal == value, t => t.SamiFirstFloorFoldartal = value); } public string Roguelike3FirstFloorFoldartals { get => GetTaskConfig().SamiFirstFloorFoldartals; set { value = value.Trim(); SetTaskConfig(t => t.SamiFirstFloorFoldartals == value, t => t.SamiFirstFloorFoldartals = value); } } /// /// Gets or sets a value indicating whether core char need start with elite two. /// public bool Roguelike3NewSquad2StartingFoldartal { get => GetTaskConfig().SamiNewSquad2StartingFoldartal; set => SetTaskConfig(t => t.SamiNewSquad2StartingFoldartal == value, t => t.SamiNewSquad2StartingFoldartal = value); } public string Roguelike3NewSquad2StartingFoldartals { get => GetTaskConfig().SamiNewSquad2StartingFoldartals; set { value = value.Replace(';', ';').Trim(); SetTaskConfig(t => t.SamiNewSquad2StartingFoldartals == value, t => t.SamiNewSquad2StartingFoldartals = value); } } /// /// Gets or sets the expected collapsal paradigms. /// 需要刷的坍缩列表,分号分隔 /// public string RoguelikeExpectedCollapsalParadigms { get => GetTaskConfig().ExpectedCollapsalParadigms; set { value = value.Replace(';', ';').Trim(); SetTaskConfig(t => t.ExpectedCollapsalParadigms == value, t => t.ExpectedCollapsalParadigms = value); } } /// /// Gets or sets a value indicating whether to use support unit. /// public bool RoguelikeUseSupportUnit { get => GetTaskConfig().UseSupport; set { if (value && RoguelikeStartWithEliteTwo && RoguelikeSquadIsProfessional) { RoguelikeStartWithEliteTwo = false; } SetTaskConfig(t => t.UseSupport == value, t => t.UseSupport = value); } } /// /// Gets or sets a value indicating whether can roguelike support unit belong to nonfriend. /// public bool RoguelikeEnableNonfriendSupport { get => GetTaskConfig().UseSupportNonFriend; set => SetTaskConfig(t => t.UseSupportNonFriend == value, t => t.UseSupportNonFriend = value); } /// /// Gets or sets the start count of roguelike. /// public int RoguelikeStartsCount { get => GetTaskConfig().StartCount; set => SetTaskConfig(t => t.StartCount == value, t => t.StartCount = value); } /// /// Gets or sets a value indicating whether investment is enabled. /// public bool RoguelikeInvestmentEnabled { get => GetTaskConfig().Investment; set => SetTaskConfig(t => t.Investment == value, t => t.Investment = value); } /// /// Gets or sets a value indicating whether investment is enabled. /// public bool RoguelikeInvestmentWithMoreScoreRaw { get => GetTaskConfig().InvestWithMoreScore; set => SetTaskConfig(t => t.InvestWithMoreScore == value, t => t.InvestWithMoreScore = value); } /// /// Gets a value indicating whether investment is enabled. /// public bool RoguelikeInvestmentWithMoreScore => GetTaskConfig().InvestWithMoreScore && RoguelikeMode == Mode.Investment; /// /// Gets or sets a value indicating whether shopping is enabled in LastReward Mode. /// public bool RoguelikeCollectibleModeShopping { get => GetTaskConfig().CollectibleShopping; set => SetTaskConfig(t => t.CollectibleShopping == value, t => t.CollectibleShopping = value); } public bool RoguelikeRefreshTraderWithDiceRaw { get => GetTaskConfig().RefreshTraderWithDice; set => SetTaskConfig(t => t.RefreshTraderWithDice == value, t => t.RefreshTraderWithDice = value); } /// /// Gets or sets the invests count of roguelike. /// public int RoguelikeInvestsCount { get => GetTaskConfig().InvestCount; set => SetTaskConfig(t => t.InvestCount == value, t => t.InvestCount = value); } /// /// Gets or sets a value indicating whether to stop when investment is full. /// public bool RoguelikeStopWhenInvestmentFull { get => GetTaskConfig().StopWhenDepositFull; set => SetTaskConfig(t => t.StopWhenDepositFull == value, t => t.StopWhenDepositFull = value); } /// /// Gets or sets a value indicating whether to stop when arriving at final boss. /// public bool RoguelikeStopAtFinalBoss { get => GetTaskConfig().StopAtFinalBoss; set => SetTaskConfig(t => t.StopAtFinalBoss == value, t => t.StopAtFinalBoss = value); } /// /// Gets or sets a value indicating whether to automatically iterate the monthly squad. /// public bool RoguelikeMonthlySquadAutoIterate { get => GetTaskConfig().MonthlySquadAutoIterate; set => SetTaskConfig(t => t.MonthlySquadAutoIterate == value, t => t.MonthlySquadAutoIterate = value); } /// /// Gets or sets a value indicating whether to automatically iterate the deep exploration mode. /// public bool RoguelikeMonthlySquadCheckComms { get => GetTaskConfig().MonthlySquadCheckComms; set => SetTaskConfig(t => t.MonthlySquadCheckComms == value, t => t.MonthlySquadCheckComms = value); } /// /// Gets or sets a value indicating whether to automatically iterate the deep exploration mode. /// public bool RoguelikeDeepExplorationAutoIterate { get => GetTaskConfig().DeepExplorationAutoIterate; set => SetTaskConfig(t => t.DeepExplorationAutoIterate == value, t => t.DeepExplorationAutoIterate = value); } /// /// Gets or sets the target playtime subnode type for FindPlaytime mode. /// public RoguelikeBoskySubNodeType RoguelikeFindPlaytimeTarget { get => GetTaskConfig().FindPlaytimeTarget; set => SetTaskConfig(t => t.FindPlaytimeTarget == value, t => t.FindPlaytimeTarget = value); } /// /// Gets the list of available playtime target options for FindPlaytime mode. /// public ObservableCollection> RoguelikeFindPlaytimeTargetList { get; } = [ new() { Display = LocalizationHelper.GetString("RoguelikePlaytimeLing"), Value = RoguelikeBoskySubNodeType.Ling }, new() { Display = LocalizationHelper.GetString("RoguelikePlaytimeShu"), Value = RoguelikeBoskySubNodeType.Shu }, new() { Display = LocalizationHelper.GetString("RoguelikePlaytimeNian"), Value = RoguelikeBoskySubNodeType.Nian }, ]; /// /// Gets a value indicating whether the FindPlaytime target selection should be visible. /// public bool RoguelikeFindPlaytimeTargetVisible => RoguelikeMode == Mode.FindPlaytime && RoguelikeTheme == Theme.JieGarden; /// /// Gets or sets a value indicating whether to stop when max level has been achieved. /// public bool RoguelikeStopAtMaxLevel { get => GetTaskConfig().StopWhenLevelMax; set => SetTaskConfig(t => t.StopWhenLevelMax == value, t => t.StopWhenLevelMax = value); } private bool _roguelikeDelayAbortUntilCombatComplete = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeDelayAbortUntilCombatComplete, bool.FalseString)); /// /// Gets or sets a value indicating whether delay abort until battle complete /// public bool RoguelikeDelayAbortUntilCombatComplete { get => _roguelikeDelayAbortUntilCombatComplete; set { SetAndNotify(ref _roguelikeDelayAbortUntilCombatComplete, value); ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeDelayAbortUntilCombatComplete, value.ToString()); } } private bool _roguelikeStartWithSeed = false; /// /// Gets or sets a value indicating whether start with seed when investing in Sarkaz. /// public bool RoguelikeStartWithSeed { get => _roguelikeStartWithSeed; set { SetAndNotify(ref _roguelikeStartWithSeed, value); } } public override void RefreshUI(BaseTask baseTask) { if (baseTask is RoguelikeTask) { UpdateRoguelikeParams(); Refresh(); } } public override void ProcSubTaskMsg(AsstMsg msg, JObject details) { if (msg != AsstMsg.SubTaskExtraInfo) { return; } var subTaskDetails = details["details"]; switch (details["what"]?.ToString() ?? string.Empty) { case "RoguelikeInvestmentReachFull": Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("RoguelikeInvestmentReachFull"), UiLogColor.Info); AchievementTrackerHelper.Instance.SetProgress(AchievementIds.RoguelikeGoldMax, 999); break; case "RoguelikeInvestmentReachLimit": Instances.TaskQueueViewModel.AddLog(string.Format(LocalizationHelper.GetString("RoguelikeInvestmentReachLimit"), subTaskDetails!["limit"]), UiLogColor.Info); break; case "RoguelikeInvestment": Instances.TaskQueueViewModel.AddLog(string.Format(LocalizationHelper.GetString("RoguelikeInvestment"), subTaskDetails!["count"], subTaskDetails["total"], subTaskDetails["deposit"]), UiLogColor.Info); AchievementTrackerHelper.Instance.SetProgress(AchievementIds.RoguelikeGoldMax, (int)subTaskDetails["deposit"]!); break; // 肉鸽结算 case "RoguelikeSettlement": { var report = subTaskDetails; var pass = (bool)report!["game_pass"]!; var difficulty = report["difficulty"]?.ToObject() ?? -1; if (difficulty < 0 || difficulty > GetMaxDifficultyForTheme(RoguelikeTheme)) { // 最后一位是 0 可能是识别错了,打个补丁 if (difficulty % 10 == 0) { difficulty /= 10; } else { difficulty = -1; } } var roguelikeInfo = string.Format( LocalizationHelper.GetString("RoguelikeSettlement"), pass ? "✓" : "✗", report["floor"], report["step"], report["combat"], report["emergency"], report["boss"], report["recruit"], report["collection"], difficulty, report["score"], report["exp"], report["skill"]); if (pass) { if (difficulty >= 4) { AchievementTrackerHelper.Instance.Unlock(AchievementIds.RoguelikeN04); } if (difficulty >= 8) { AchievementTrackerHelper.Instance.Unlock(AchievementIds.RoguelikeN08); } if (difficulty >= 12) { AchievementTrackerHelper.Instance.Unlock(AchievementIds.RoguelikeN12); } if (difficulty >= 15) { AchievementTrackerHelper.Instance.Unlock(AchievementIds.RoguelikeN15); } } Instances.TaskQueueViewModel.AddLog(roguelikeInfo, UiLogColor.Message, updateCardImage: true); break; } case "RoguelikeCombatEnd": // 肉鸽战斗结束,无论成功与否 Instances.TaskQueueViewModel.RoguelikeInCombatAndShowWait = false; break; case "RoguelikeEvent": Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("RoguelikeEvent") + $" {subTaskDetails!["name"]}", UiLogColor.EventIS); break; case "RoguelikeEncounterOptions": var options = (subTaskDetails!["options"]! as JArray) ?? []; var logLines = new List { string.Format(LocalizationHelper.GetString("RoguelikeEncounterOptions"), options.Count, UiLogColor.EventIS), }; foreach (var option in options) { string messageKey = option["enabled"]!.Value() ? "RoguelikeEncounterEnabledOption" : "RoguelikeEncounterDisabledOption"; var text = option["text"]!.ToString(); logLines.Add(string.Format(LocalizationHelper.GetString(messageKey), text)); } Instances.TaskQueueViewModel.AddLog(string.Join("\n", logLines), UiLogColor.EventIS, updateCardImage: true); break; case "BoskyPassageNode": { var nodeType = subTaskDetails!["node_type"]?.ToString(); var (localizedNodeType, logColor) = nodeType switch { "Omissions" => (LocalizationHelper.GetString("BoskyOmissions"), UiLogColor.BoskyOmissionsIS), "Legend" => (LocalizationHelper.GetString("BoskyLegend"), UiLogColor.BoskyLegendIS), "OldShop" => (LocalizationHelper.GetString("BoskyOldShop"), UiLogColor.BoskyOldShopIS), "YiTrader" => (LocalizationHelper.GetString("BoskyYiTrader"), UiLogColor.TraderIS), "Scheme" => (LocalizationHelper.GetString("BoskyScheme"), UiLogColor.BoskySchemeIS), "Playtime" => (LocalizationHelper.GetString("BoskyPlaytime"), UiLogColor.BoskyPlaytimeIS), "Doubts" => (LocalizationHelper.GetString("BoskyDoubts"), UiLogColor.BoskyDoubtsIS), "Disaster" => (LocalizationHelper.GetString("BoskyDisaster"), UiLogColor.EmergencyIS), _ => (nodeType ?? "Unknown", UiLogColor.EventIS), }; Instances.TaskQueueViewModel.AddLog(localizedNodeType, logColor); break; } case "RoguelikeCoppersRecognitionError": { var recognizedName = subTaskDetails!["recognized_name"]?.ToString() ?? "Unknown"; var message = string.Format(LocalizationHelper.GetString("RoguelikeCoppersRecognitionError"), recognizedName); Instances.TaskQueueViewModel.AddLog(message, UiLogColor.Error); break; } case "RoguelikeCoppersExchangeInfo": { var toDiscard = subTaskDetails!["to_discard"]?.ToString() ?? "Unknown"; var toPickup = subTaskDetails["to_pickup"]?.ToString() ?? "Unknown"; var message = string.Format(LocalizationHelper.GetString("RoguelikeCoppersExchange"), toDiscard, toPickup); Instances.TaskQueueViewModel.AddLog(message, UiLogColor.EventIS); break; } case "EncounterOcrError": Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("EncounterOcrError"), UiLogColor.Error); break; case "RoguelikeJieGardenTargetFound": { var targetSubtype = subTaskDetails!["target_subtype"]?.ToString(); var localizedTarget = targetSubtype switch { "Ling" => LocalizationHelper.GetString("RoguelikePlaytimeLing"), "Shu" => LocalizationHelper.GetString("RoguelikePlaytimeShu"), "Nian" => LocalizationHelper.GetString("RoguelikePlaytimeNian"), _ => targetSubtype ?? "Unknown", }; Instances.TaskQueueViewModel.AddLog(string.Format(LocalizationHelper.GetString("RoguelikeJieGardenTargetFound"), localizedTarget), UiLogColor.Success); break; } case "FoldartalGainOcrNextLevel": Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("FoldartalGainOcrNextLevel") + $" {subTaskDetails!["foldartal"]}"); break; case "MonthlySquadCompleted": Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("MonthlySquadCompleted"), UiLogColor.RareOperator); break; case "DeepExplorationCompleted": Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("DeepExplorationCompleted"), UiLogColor.RareOperator); break; case "RoguelikeCollapsalParadigms": string deepen_or_weaken_str = subTaskDetails!["deepen_or_weaken"]?.ToString() ?? "Unknown"; if (!int.TryParse(deepen_or_weaken_str, out int deepen_or_weaken)) { break; } string cur = subTaskDetails["cur"]?.ToString() ?? "UnKnown"; string prev = subTaskDetails["prev"]?.ToString() ?? "UnKnown"; if (deepen_or_weaken == 1 && prev == string.Empty) { Instances.TaskQueueViewModel.AddLog(string.Format(LocalizationHelper.GetString("RoguelikeGainParadigm"), cur), UiLogColor.Info); } else if (deepen_or_weaken == 1 && prev != string.Empty) { Instances.TaskQueueViewModel.AddLog(string.Format(LocalizationHelper.GetString("RoguelikeDeepenParadigm"), cur, prev), UiLogColor.Info); } else if (deepen_or_weaken == -1 && cur == string.Empty) { Instances.TaskQueueViewModel.AddLog(string.Format(LocalizationHelper.GetString("RoguelikeLoseParadigm"), string.Empty, prev), UiLogColor.Info); } else if (deepen_or_weaken == -1 && cur != string.Empty) { Instances.TaskQueueViewModel.AddLog(string.Format(LocalizationHelper.GetString("RoguelikeWeakenParadigm"), cur, prev), UiLogColor.Info); } break; } } [Obsolete("使用SerializeTask作为代替")] public override (AsstTaskType Type, JObject Params) Serialize() { var task = new AsstRoguelikeTask() { Theme = RoguelikeTheme, Mode = RoguelikeMode, Starts = RoguelikeStartsCount, Difficulty = RoguelikeDifficulty, Squad = RoguelikeSquad, Roles = RoguelikeRoles, CoreChar = DataHelper.GetCharacterByNameOrAlias(RoguelikeCoreChar)?.Name ?? RoguelikeCoreChar, UseSupport = !string.IsNullOrEmpty(RoguelikeCoreChar) && RoguelikeUseSupportUnit, UseSupportNonFriend = RoguelikeEnableNonfriendSupport, InvestmentEnabled = RoguelikeInvestmentEnabled, InvestmentCount = RoguelikeInvestsCount, InvestmentStopWhenFull = RoguelikeStopWhenInvestmentFull && RoguelikeMode != Mode.Collectible, InvestmentWithMoreScore = RoguelikeInvestmentWithMoreScoreRaw && RoguelikeMode == Mode.Investment, RefreshTraderWithDice = RoguelikeTheme == Theme.Mizuki && RoguelikeRefreshTraderWithDiceRaw, StopAtFinalBoss = RoguelikeStopAtFinalBoss, StopAtMaxLevel = RoguelikeStopAtMaxLevel, // 刷开局 CollectibleModeSquad = RoguelikeCollectibleModeSquad, CollectibleModeShopping = RoguelikeCollectibleModeShopping, StartWithEliteTwo = RoguelikeStartWithEliteTwo && RoguelikeSquadIsProfessional && RoguelikeTheme is Theme.Mizuki or Theme.Sami, StartWithEliteTwoNonBattle = RoguelikeOnlyStartWithEliteTwo && RoguelikeTheme is Theme.Mizuki or Theme.Sami, // 月度小队 MonthlySquadAutoIterate = RoguelikeMonthlySquadAutoIterate, MonthlySquadCheckComms = RoguelikeMonthlySquadCheckComms, // 深入探索 DeepExplorationAutoIterate = RoguelikeDeepExplorationAutoIterate, // 刷常乐节点 FindPlaytimeTarget = RoguelikeFindPlaytimeTarget, SamiFirstFloorFoldartal = RoguelikeTheme == Theme.Sami && RoguelikeMode == Mode.Collectible && Roguelike3FirstFloorFoldartal, SamiStartFloorFoldartal = Roguelike3FirstFloorFoldartals, SamiNewSquad2StartingFoldartal = Roguelike3NewSquad2StartingFoldartal && RoguelikeSquadIsFoldartal, SamiNewSquad2StartingFoldartals = Roguelike3NewSquad2StartingFoldartals.Split(';').Where(i => !string.IsNullOrEmpty(i)).Take(3).ToList(), ExpectedCollapsalParadigms = RoguelikeExpectedCollapsalParadigms.Split(';').Where(i => !string.IsNullOrEmpty(i)).ToList(), StartWithSeed = RoguelikeStartWithSeed && RoguelikeTheme == Theme.Sarkaz && RoguelikeMode == Mode.Investment && RoguelikeSquad is "点刺成锭分队" or "后勤分队", }; if (RoguelikeMode == Mode.Collectible && !RoguelikeOnlyStartWithEliteTwo) { var rewardKeys = new Dictionary { { RoguelikeCollectibleAward.HotWater, "hot_water" }, { RoguelikeCollectibleAward.Shield, "shield" }, { RoguelikeCollectibleAward.Ingot, "ingot" }, { RoguelikeCollectibleAward.Hope, "hope" }, { RoguelikeCollectibleAward.Random, "random" }, { RoguelikeCollectibleAward.Key, "key" }, { RoguelikeCollectibleAward.Dice, "dice" }, { RoguelikeCollectibleAward.Idea, "ideas" }, { RoguelikeCollectibleAward.Ticket, "ticket" }, }; var startWithSelect = new JObject(); foreach (var select in RoguelikeStartWithSelectList.Cast>()) { if (rewardKeys.TryGetValue(select.Value, out var paramKey)) { task.CollectibleModeStartRewards[paramKey] = true; } } } return task.Serialize(); } public override bool? SerializeTask(BaseTask? baseTask, int? taskId = null) { if (baseTask is not RoguelikeTask roguelike) { return null; } bool roguelikeSquadIsProfessional = roguelike.Mode == Mode.Collectible && roguelike.Theme != Theme.Phantom && roguelike.Squad is "突击战术分队" or "堡垒战术分队" or "远程战术分队" or "破坏战术分队"; bool roguelikeSquadIsFoldartal = roguelike.Mode == Mode.Collectible && roguelike.Theme == Theme.Sami && roguelike.Squad == "生活至上分队"; var task = new AsstRoguelikeTask() { Theme = roguelike.Theme, Mode = roguelike.Mode, Starts = roguelike.StartCount, Difficulty = roguelike.Difficulty, Squad = roguelike.Squad, Roles = roguelike.Roles, CoreChar = DataHelper.GetCharacterByNameOrAlias(roguelike.CoreChar)?.Name ?? roguelike.CoreChar, UseSupport = roguelike.UseSupport, UseSupportNonFriend = roguelike.UseSupportNonFriend, InvestmentEnabled = roguelike.Investment, InvestmentCount = roguelike.InvestCount, InvestmentStopWhenFull = roguelike.StopWhenDepositFull, InvestmentWithMoreScore = roguelike.InvestWithMoreScore && roguelike.Mode == Mode.Investment, RefreshTraderWithDice = roguelike.Theme == Theme.Mizuki && roguelike.RefreshTraderWithDice, StopAtFinalBoss = roguelike.StopAtFinalBoss, StopAtMaxLevel = roguelike.StopWhenLevelMax, // 刷开局 CollectibleModeSquad = roguelike.SquadCollectible, CollectibleModeShopping = roguelike.CollectibleShopping, StartWithEliteTwo = roguelike.StartWithEliteTwo && roguelikeSquadIsProfessional && roguelike.Theme is Theme.Mizuki or Theme.Sami, StartWithEliteTwoNonBattle = roguelike.StartWithEliteTwoOnly && roguelike.Theme is Theme.Mizuki or Theme.Sami, // 月度小队 MonthlySquadAutoIterate = roguelike.MonthlySquadAutoIterate, MonthlySquadCheckComms = roguelike.MonthlySquadCheckComms, // 深入探索 DeepExplorationAutoIterate = roguelike.DeepExplorationAutoIterate, // 刷常乐节点 FindPlaytimeTarget = roguelike.FindPlaytimeTarget, // 等待添加到 RoguelikeTask SamiFirstFloorFoldartal = roguelike.Theme == Theme.Sami && roguelike.Mode == Mode.Collectible && roguelike.SamiFirstFloorFoldartal, SamiStartFloorFoldartal = roguelike.SamiFirstFloorFoldartals, SamiNewSquad2StartingFoldartal = roguelike.SamiNewSquad2StartingFoldartal && roguelikeSquadIsFoldartal, SamiNewSquad2StartingFoldartals = [.. roguelike.SamiNewSquad2StartingFoldartals.Split(';').Where(i => !string.IsNullOrEmpty(i)).Take(3)], ExpectedCollapsalParadigms = [.. roguelike.ExpectedCollapsalParadigms.Split(';').Where(i => !string.IsNullOrEmpty(i))], // StartWithSeed = roguelike.StartWithSeed && RoguelikeTheme == Theme.Sarkaz && RoguelikeMode == Mode.Investment && RoguelikeSquad is "点刺成锭分队" or "后勤分队", }; if (RoguelikeMode == Mode.Collectible && !RoguelikeOnlyStartWithEliteTwo) { var rewardKeys = new Dictionary { { RoguelikeCollectibleAward.HotWater, "hot_water" }, { RoguelikeCollectibleAward.Shield, "shield" }, { RoguelikeCollectibleAward.Ingot, "ingot" }, { RoguelikeCollectibleAward.Hope, "hope" }, { RoguelikeCollectibleAward.Random, "random" }, { RoguelikeCollectibleAward.Key, "key" }, { RoguelikeCollectibleAward.Dice, "dice" }, { RoguelikeCollectibleAward.Idea, "ideas" }, { RoguelikeCollectibleAward.Ticket, "ticket" }, }; var startWithSelect = new JObject(); foreach (var select in RoguelikeStartWithSelectList.Cast>()) { if (rewardKeys.TryGetValue(select.Value, out var paramKey)) { task.CollectibleModeStartRewards[paramKey] = true; } } } return taskId switch { int id when id > 0 => Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), null => Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Roguelike, task), _ => null, }; } }