diff --git a/resource/tasks/Stages/MT.json b/resource/tasks/Stages/MT.json index 0c08072575..20ce4b6acb 100644 --- a/resource/tasks/Stages/MT.json +++ b/resource/tasks/Stages/MT.json @@ -53,6 +53,19 @@ "text": ["众生行记", "谒见神祇", "见神", "息止安所"], "next": ["MTChapterToMT"] }, + "MT-OpenTask": { + "algorithm": "JustReturn", + "next": ["MT-OpenTask@SS-Open", "MT-OpenTask@SS-OpenOcr"] + }, + "MT-OpenTask@SS-Open": { + "baseTask": "SS-Open", + "template": ["StageSideStory.png", "StageActivity.png"], + "next": ["MT@SS@EnterTaskPage"] + }, + "MT-OpenTask@SS-OpenOcr": { + "baseTask": "SS-OpenOcr", + "next": ["MT@SS@EnterTaskPage"] + }, "MTChapterToMT": { "algorithm": "OcrDetect", "action": "ClickSelf", @@ -60,5 +73,10 @@ "preDelay": 4000, "roi": [622, 588, 234, 132], "next": ["#self", "ChapterSwipeToTheRight"] + }, + "MT@SS@EnterTaskPage": { + "text": ["哄睡", "指标"], + "roi": [1100, 175, 140, 40], + "ocrReplace": [["指标", "指示"]] } } diff --git a/resource/tasks/Stages/base.json b/resource/tasks/Stages/base.json index 881aa55e96..4c70d57bdc 100644 --- a/resource/tasks/Stages/base.json +++ b/resource/tasks/Stages/base.json @@ -87,5 +87,26 @@ "next": ["SS@Store@ClickItem", "#self"], "maxTimes": 10, "exceededNext": ["Stop"] + }, + "SS@EnterTaskPage": { + "algorithm": "OcrDetect", + "action": "ClickSelf", + "text": [], + "preDelay": 4000, + "onErrorNext": ["Return"], + "next": ["SS@ClaimTask", "#self"] + }, + "SS@ClaimTask": { + "algorithm": "OcrDetect", + "action": "ClickSelf", + "text": ["领取"], + "postDelay": 2000, + "roi": [980, 140, 240, 70], + "next": ["SS@ClaimTaskSuccess", "#self"] + }, + "SS@ClaimTaskSuccess": { + "baseTask": "CreditShop-Bought", + "template": "CreditShop-Bought.png", + "next": ["ReturnButtonCheck", "#self"] } } diff --git a/resource/tasks/tasks.json b/resource/tasks/tasks.json index 18c39d4fa2..8677d0e9d1 100644 --- a/resource/tasks/tasks.json +++ b/resource/tasks/tasks.json @@ -1082,6 +1082,13 @@ ], "onErrorNext": ["SwitchTheme@ToggleSettingsMenu"] }, + "ReturnButtonCheck": { + "baseTask": "ReturnButton", + "template": ["Return.png", "Return-White.png"], + "action": "DoNothing", + "next": [], + "onErrorNext": [] + }, "FromStageSN": { "template": "StageSNReturnFlag.png", "action": "ClickRect", diff --git a/src/MaaCore/Task/Interface/SideStoryTask.cpp b/src/MaaCore/Task/Interface/SideStoryTask.cpp new file mode 100644 index 0000000000..1ec071770e --- /dev/null +++ b/src/MaaCore/Task/Interface/SideStoryTask.cpp @@ -0,0 +1,90 @@ +#include "SideStoryTask.h" + +#include +#include + +#include "Config/TaskData.h" +#include "Task/Fight/SideStoryReopenTask.h" +#include "Task/Fight/StageDropsTaskPlugin.h" +#include "Task/Fight/StageNavigationTask.h" +#include "Task/ProcessTask.h" +#include "Utils/Logger.hpp" + +asst::SideStoryTask::SideStoryTask(const AsstCallback& callback, Assistant* inst) : + InterfaceTask(callback, inst, TaskType), + m_start_up_task_ptr(std::make_shared(m_callback, m_inst, TaskType)), + m_stage_navigation_task_ptr(std::make_shared(m_callback, m_inst, TaskType)), + m_sidestory_reopen_task_ptr(std::make_shared(m_callback, m_inst, TaskType)), + m_claim_task_task_ptr(std::make_shared(m_callback, m_inst, TaskType)) +{ + LogTraceFunction; + + // 进入选关界面 + // 对于指定关卡,就是主界面的“终端”点进去 + // 对于当前/上次,就是点到 蓝色开始行动 为止。 + m_start_up_task_ptr->set_tasks({ "StageBegin" }) + .set_times_limit("GoLastBattle", 0) + .set_times_limit("StartButton1", 0) + .set_times_limit("StartButton2", 0) + .set_times_limit("StoneConfirm", 0) + .set_times_limit("StageSNReturnFlag", 0) + .set_times_limit("PRTS1", 0) + .set_times_limit("PRTS2", 0) + .set_times_limit("PRTS3", 0) + .set_times_limit("EndOfAction", 0) + .set_retry_times(5); + m_start_up_task2_ptr->set_tasks({ "StageBegin" }) + .set_times_limit("GoLastBattle", 0) + .set_times_limit("StartButton1", 0) + .set_times_limit("StartButton2", 0) + .set_times_limit("StoneConfirm", 0) + .set_times_limit("StageSNReturnFlag", 0) + .set_times_limit("PRTS1", 0) + .set_times_limit("PRTS2", 0) + .set_times_limit("PRTS3", 0) + .set_times_limit("EndOfAction", 0) + .set_retry_times(5); + + m_stage_navigation_task_ptr->set_retry_times(0); + m_stage_navigation_task2_ptr->set_retry_times(0); + m_sidestory_reopen_task_ptr->set_enable(false).set_retry_times(0); + + m_subtasks.emplace_back(m_start_up_task_ptr); + m_subtasks.emplace_back(m_stage_navigation_task_ptr); + m_subtasks.emplace_back(m_sidestory_reopen_task_ptr); + m_subtasks.emplace_back(m_start_up_task2_ptr); + m_subtasks.emplace_back(m_stage_navigation_task2_ptr); + m_subtasks.emplace_back(m_claim_task_task_ptr); +} + +bool asst::SideStoryTask::set_params(const json::value& params) +{ + LogTraceFunction; + + const std::string code = params.get("code", ""); + if (!Task.get(code + "-OpenOpt")) { + return false; + } + + const bool stage_replay = params.get("stage_replay", false); + m_start_up_task_ptr->set_enable(stage_replay); + m_stage_navigation_task_ptr->set_enable(stage_replay); + m_sidestory_reopen_task_ptr->set_enable(stage_replay); + if (stage_replay) { + m_stage_navigation_task_ptr->set_stage_name(code + "-OpenOpt"); + } + + const bool award = params.get("award", false); + if (award) { + if (!Task.get(code + "-OpenTask")) { + LogError << "claim task not exists:" << code + "-OpenTask"; + return false; + } + m_claim_task_task_ptr->set_tasks({ code + "-OpenTask" }).set_retry_times(20); + } + m_start_up_task2_ptr->set_enable(award); + m_stage_navigation_task2_ptr->set_enable(award); + m_claim_task_task_ptr->set_enable(award); + + return true; +} diff --git a/src/MaaCore/Task/Interface/SideStoryTask.h b/src/MaaCore/Task/Interface/SideStoryTask.h new file mode 100644 index 0000000000..4c6882d781 --- /dev/null +++ b/src/MaaCore/Task/Interface/SideStoryTask.h @@ -0,0 +1,30 @@ +#pragma once +#include "Task/InterfaceTask.h" + +#include + +namespace asst +{ +class ProcessTask; +class StageNavigationTask; +class SideStoryReopenTask; + +class SideStoryTask final : public InterfaceTask +{ +public: + inline static constexpr std::string_view TaskType = "SideStory"; + + SideStoryTask(const AsstCallback& callback, Assistant* inst); + virtual ~SideStoryTask() override = default; + + virtual bool set_params(const json::value& params) override; + +protected: + std::shared_ptr m_start_up_task_ptr = nullptr; + std::shared_ptr m_start_up_task2_ptr = nullptr; + std::shared_ptr m_stage_navigation_task_ptr = nullptr; + std::shared_ptr m_stage_navigation_task2_ptr = nullptr; + std::shared_ptr m_sidestory_reopen_task_ptr = nullptr; + std::shared_ptr m_claim_task_task_ptr = nullptr; +}; +} diff --git a/src/MaaWpfGui/Configuration/Single/MaaTask/SideStoryTask.cs b/src/MaaWpfGui/Configuration/Single/MaaTask/SideStoryTask.cs new file mode 100644 index 0000000000..e4cfb9e2cb --- /dev/null +++ b/src/MaaWpfGui/Configuration/Single/MaaTask/SideStoryTask.cs @@ -0,0 +1,26 @@ +// +// 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 static MaaWpfGui.Main.AsstProxy; + +namespace MaaWpfGui.Configuration.Single.MaaTask; + +public class SideStoryTask : BaseTask +{ + public SideStoryTask() => TaskType = TaskType.SideStory; + + /// + /// Gets or sets 上次活动的StageCode, 用于判断活动是否更新 + /// + public string StageCode { get; set; } = string.Empty; +} diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs index 8b3ca8050d..a20b10e1d5 100644 --- a/src/MaaWpfGui/Main/AsstProxy.cs +++ b/src/MaaWpfGui/Main/AsstProxy.cs @@ -2862,10 +2862,13 @@ public class AsstProxy /// 更新用户数据 UserDataUpdate, + /// Side Story + SideStory, + /// 小游戏 MiniGame, - /// 自定义任务s + /// 自定义任务 Custom, } diff --git a/src/MaaWpfGui/Models/AsstTasks/AsstSideStoryTask.cs b/src/MaaWpfGui/Models/AsstTasks/AsstSideStoryTask.cs new file mode 100644 index 0000000000..3a6531a0b6 --- /dev/null +++ b/src/MaaWpfGui/Models/AsstTasks/AsstSideStoryTask.cs @@ -0,0 +1,34 @@ +// +// 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 +// + +using MaaWpfGui.Services; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace MaaWpfGui.Models.AsstTasks; + +public class AsstSideStoryTask : AsstBaseTask +{ + public override AsstTaskType TaskType => AsstTaskType.SideStory; + + /// + /// Gets or sets 客户端版本 + /// + [JsonProperty("stage")] + public string StageCode { get; set; } = string.Empty; + + public override (AsstTaskType TaskType, JObject Params) Serialize() + { + return (TaskType, JObject.FromObject(this)); + } +} diff --git a/src/MaaWpfGui/Models/TaskSettingVisibilityInfo.cs b/src/MaaWpfGui/Models/TaskSettingVisibilityInfo.cs index 435e430058..4bf9592681 100644 --- a/src/MaaWpfGui/Models/TaskSettingVisibilityInfo.cs +++ b/src/MaaWpfGui/Models/TaskSettingVisibilityInfo.cs @@ -54,6 +54,8 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase public bool UserDataUpdate { get => field; set => SetAndNotify(ref field, value); } + public bool SideStory { get => field; set => SetAndNotify(ref field, value); } + public bool Custom { get => field; set => SetAndNotify(ref field, value); } public bool PostAction { get => field; set => SetAndNotify(ref field, value); } @@ -148,6 +150,7 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase RoguelikeTask => Roguelike = enable, ReclamationTask => Reclamation = enable, UserDataUpdateTask => UserDataUpdate = enable, + SideStoryTask => SideStory = enable, CustomTask => Custom = enable, _ => throw new NotImplementedException(), }; @@ -188,6 +191,7 @@ public class TaskSettingVisibilityInfo : PropertyChangedBase Roguelike = false; Reclamation = false; UserDataUpdate = false; + SideStory = false; Custom = false; } diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml index 0c15ead496..2c780cc522 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml @@ -859,6 +859,9 @@ C:\\leidian\\LDPlayer9。\n 周一了,可以打剿灭了~ 周日了,记得打剿灭哦~ + + 活动复刻: 「{0}」 + UI 和 Core 版本不一致: {0} 和 {1},可能导致不可预测的行为,请勿手动替换文件或者在更新时占用文件。\n\n{key=FullPackageUpgradeTips} 请下载完整包并解压到新的文件夹,切勿直接覆盖原文件夹。\n可将原有的 config、data 与 debug 文件夹复制到新文件夹中,以保留原有配置和日志。 diff --git a/src/MaaWpfGui/Services/MaaService.cs b/src/MaaWpfGui/Services/MaaService.cs index 4608962a94..679e55dfb9 100644 --- a/src/MaaWpfGui/Services/MaaService.cs +++ b/src/MaaWpfGui/Services/MaaService.cs @@ -185,6 +185,11 @@ public enum AsstTaskType : byte /// Reclamation, + /// + /// SideStory + /// + SideStory, + /// /// 自定义任务 /// diff --git a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs index 1778253f40..7efe320d08 100644 --- a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs @@ -29,7 +29,6 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; using JetBrains.Annotations; -using MaaWpfGui.Configuration; using MaaWpfGui.Configuration.Factory; using MaaWpfGui.Configuration.Single.MaaTask; using MaaWpfGui.Constants; @@ -134,7 +133,12 @@ public class TaskQueueViewModel : Screen public static UserDataUpdateSettingsUserControlModel UserDataUpdateTask => UserDataUpdateSettingsUserControlModel.Instance; /// - /// Gets 生稀盐酸任务Model + /// Gets SideStory任务Model + /// + public static SideStorySettingsUserControlModel SideStoryTask => SideStorySettingsUserControlModel.Instance; + + /// + /// Gets 自定任务Model /// public static CustomSettingsUserControlModel CustomTask => CustomSettingsUserControlModel.Instance; @@ -1332,6 +1336,7 @@ public class TaskQueueViewModel : Screen new GenericCombinedData { Display = LocalizationHelper.GetString("Roguelike"), Value = typeof(RoguelikeTask) }, new GenericCombinedData { Display = LocalizationHelper.GetString("Reclamation"), Value = typeof(ReclamationTask) }, new GenericCombinedData { Display = LocalizationHelper.GetString("UserDataUpdate"), Value = typeof(UserDataUpdateTask) }, + new GenericCombinedData { Display = LocalizationHelper.GetString("SideStoryTask"), Value = typeof(SideStoryTask) }, new GenericCombinedData { Display = LocalizationHelper.GetString("Custom"), Value = typeof(CustomTask) }, ]); diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/SideStorySettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/SideStorySettingsUserControlModel.cs new file mode 100644 index 0000000000..0524204327 --- /dev/null +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/SideStorySettingsUserControlModel.cs @@ -0,0 +1,87 @@ +// +// 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.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using MaaWpfGui.Configuration.Single.MaaTask; +using MaaWpfGui.Helper; +using MaaWpfGui.Models.AsstTasks; +using Stylet; +using static MaaWpfGui.Main.AsstProxy; + +namespace MaaWpfGui.ViewModels.UserControl.TaskQueue; + +public class SideStorySettingsUserControlModel : TaskSettingsViewModel, SideStorySettingsUserControlModel.ISerialize +{ + static SideStorySettingsUserControlModel() + { + Instance = new(); + } + + public static SideStorySettingsUserControlModel Instance { get; } + + public bool TaskAward { get => field; set => SetAndNotify(ref field, value); } = true; + + public bool StageReopen { get => field; set => SetAndNotify(ref field, value); } = true; + + public ObservableCollection StageList { get; set; } = [.. Enumerable.Range(1, 10).Select(i => new StageItem(i))]; + + public bool IsSideStoryReopenEnable { get => field; set => SetAndNotify(ref field, value); } + + public string ActivityInfo { get => field; private set => SetAndNotify(ref field, value); } = string.Empty; + + public override void RefreshUI(BaseTask baseTask) + { + if (Instances.StageManager.ActivityList.TryGetValue("SSReopen", out var activity)) + { + IsSideStoryReopenEnable = true; + ActivityInfo = $"{LocalizationHelper.GetStringFormat("SideStoryReopen", activity.Info.StageName)}"; + } + else + { + ActivityInfo = LocalizationHelper.GetString("NoActivity"); + IsSideStoryReopenEnable = false; + } + } + + public override (bool? IsSuccess, IEnumerable TaskId) SerializeTask(BaseTask? baseTask, int? taskId = null) => (this as ISerialize).Serialize(baseTask, taskId); + + public class StageItem(int stage) : PropertyChangedBase + { + private int Stage = stage; + + public string Display => "MT-" + Stage.ToString(); + + public bool Value { get => field; set => SetAndNotify(ref field, value); } = true; + } + + private interface ISerialize : ITaskQueueModelSerialize + { + (bool? IsSuccess, IEnumerable TaskId) ITaskQueueModelSerialize.Serialize(BaseTask? baseTask, int? taskId) + { + if (baseTask is not CustomTask custom) + { + return (null, []); + } + + var task = new AsstCustomTask() { }; + return taskId switch { + int id when id > 0 => (Instances.AsstProxy.AsstSetTaskParamsEncoded(id, task), [id]), + null => FromSingle(Instances.AsstProxy.AsstAppendTaskWithEncoding(TaskType.Custom, task)), + _ => (null, []), + }; + } + } +} diff --git a/src/MaaWpfGui/Views/UI/TaskQueueView.xaml b/src/MaaWpfGui/Views/UI/TaskQueueView.xaml index 4a65ecf527..e180ad42ee 100644 --- a/src/MaaWpfGui/Views/UI/TaskQueueView.xaml +++ b/src/MaaWpfGui/Views/UI/TaskQueueView.xaml @@ -373,7 +373,12 @@ Padding="0,3" Command="{s:Action AddTaskQueueTask}" CommandParameter="{Binding TaskTypeList[9].Value}" - Header="{Binding TaskTypeList[9].Display}" + Header="{Binding TaskTypeList[9].Display}" /> + @@ -608,6 +613,12 @@ Visibility="{c:Binding DataContext.TaskSettingVisibilities.UserDataUpdate, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" /> + diff --git a/src/MaaWpfGui/Views/UserControl/TaskQueue/SideStorySettingsUserControl.xaml b/src/MaaWpfGui/Views/UserControl/TaskQueue/SideStorySettingsUserControl.xaml new file mode 100644 index 0000000000..3b86eb3a90 --- /dev/null +++ b/src/MaaWpfGui/Views/UserControl/TaskQueue/SideStorySettingsUserControl.xaml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/MaaWpfGui/Views/UserControl/TaskQueue/SideStorySettingsUserControl.xaml.cs b/src/MaaWpfGui/Views/UserControl/TaskQueue/SideStorySettingsUserControl.xaml.cs new file mode 100644 index 0000000000..c1bd3cfed3 --- /dev/null +++ b/src/MaaWpfGui/Views/UserControl/TaskQueue/SideStorySettingsUserControl.xaml.cs @@ -0,0 +1,28 @@ +// +// 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 +// + +namespace MaaWpfGui.Views.UserControl.TaskQueue; + +/// +/// CustomUserControl.xaml 的交互逻辑 +/// +public partial class SideStorySettingsUserControl : System.Windows.Controls.UserControl +{ + /// + /// Initializes a new instance of the class. + /// + public SideStorySettingsUserControl() + { + InitializeComponent(); + } +}