diff --git a/resource/tasks.json b/resource/tasks.json
index d62dd92e06..e869d21ff0 100644
--- a/resource/tasks.json
+++ b/resource/tasks.json
@@ -610,6 +610,27 @@
50
]
},
+ "ChangeToAdverseDifficulty": {
+ "template": "AdverseDifficulty.png",
+ "action": "ClickSelf",
+ "roi": [
+ 625,
+ 640,
+ 80,
+ 65
+ ],
+ "maxTimes": 3,
+ "next": [
+ "AdverseConfirm",
+ "#self"
+ ]
+ },
+ "AdverseConfirm": {
+ "baseTask": "ChangeToAdverseDifficulty",
+ "action": "DoNothing",
+ "template": "NormalDifficulty.png",
+ "next": []
+ },
"Episode": {
"Doc": "base_task",
"algorithm": "JustReturn",
@@ -7021,6 +7042,12 @@
"Stop"
]
},
+ "BattleQuickFormationCheck": {
+ "baseTask": "BattleQuickFormation",
+ "template": "BattleQuickFormation.png",
+ "action": "DoNothing",
+ "next": []
+ },
"BattleQuickFormation": {
"action": "ClickSelf",
"roi": [
@@ -13097,6 +13124,16 @@
"baseTask": "BattleStartPre",
"action": "DoNothing"
},
+ "Copilot@BattleStartPreFlag": {
+ "baseTask": "BattleStartPre",
+ "action": "DoNothing",
+ "roi":[
+ 0,
+ 0,
+ 1280,
+ 720
+ ]
+ },
"BattleFormationOCRNameFlag": {
"templThreshold": 0.6,
"roi": [
diff --git a/resource/template/AdverseDifficulty.png b/resource/template/AdverseDifficulty.png
new file mode 100644
index 0000000000..56b49bfa60
Binary files /dev/null and b/resource/template/AdverseDifficulty.png differ
diff --git a/resource/template/NormalDifficulty.png b/resource/template/NormalDifficulty.png
new file mode 100644
index 0000000000..beeae97437
Binary files /dev/null and b/resource/template/NormalDifficulty.png differ
diff --git a/src/MaaCore/MaaCore.vcxproj b/src/MaaCore/MaaCore.vcxproj
index 4d63e1a6a0..c1e125718e 100644
--- a/src/MaaCore/MaaCore.vcxproj
+++ b/src/MaaCore/MaaCore.vcxproj
@@ -73,8 +73,10 @@
+
+
@@ -234,8 +236,10 @@
+
+
diff --git a/src/MaaCore/MaaCore.vcxproj.filters b/src/MaaCore/MaaCore.vcxproj.filters
index f3a8ed3d92..ae11bef9b1 100644
--- a/src/MaaCore/MaaCore.vcxproj.filters
+++ b/src/MaaCore/MaaCore.vcxproj.filters
@@ -633,6 +633,12 @@
源文件\Task\Infrast
+
+ 源文件\Task\Miscellaneous
+
+
+ 源文件\Task\Miscellaneous
+
@@ -1049,5 +1055,11 @@
源文件\Task\Infrast
+
+ 源文件\Task\Miscellaneous
+
+
+ 源文件\Task\Miscellaneous
+
\ No newline at end of file
diff --git a/src/MaaCore/Task/Interface/CopilotTask.cpp b/src/MaaCore/Task/Interface/CopilotTask.cpp
index 2fffa38a47..42a5b45590 100644
--- a/src/MaaCore/Task/Interface/CopilotTask.cpp
+++ b/src/MaaCore/Task/Interface/CopilotTask.cpp
@@ -3,33 +3,48 @@
#include
#include "Config/Miscellaneous/CopilotConfig.h"
+#include "Config/TaskData.h"
#include "Task/Miscellaneous/BattleFormationTask.h"
#include "Task/Miscellaneous/BattleProcessTask.h"
+#include "Task/Miscellaneous/CopilotListNotificationPlugin.h"
+#include "Task/Miscellaneous/TaskFileReloadTask.h"
#include "Task/ProcessTask.h"
#include "Utils/Logger.hpp"
#include "Utils/Platform.hpp"
asst::CopilotTask::CopilotTask(const AsstCallback& callback, Assistant* inst)
: InterfaceTask(callback, inst, TaskType),
+ m_task_file_reload_task_ptr(std::make_shared(callback, inst, TaskType)),
+ m_navigate_task_ptr(std::make_shared(callback, inst, TaskType)),
+ m_not_use_prts_task_ptr(std::make_shared(callback, inst, TaskType)),
+ m_adverse_select_task_ptr(std::make_shared(callback, inst, TaskType)),
m_formation_task_ptr(std::make_shared(callback, inst, TaskType)),
m_battle_task_ptr(std::make_shared(callback, inst, TaskType)),
m_stop_task_ptr(std::make_shared(callback, inst, TaskType))
{
LogTraceFunction;
+ m_subtasks.emplace_back(m_task_file_reload_task_ptr);
+ m_subtasks.emplace_back(m_navigate_task_ptr);
+ m_subtasks.emplace_back(m_not_use_prts_task_ptr);
+
+ // 选择突袭模式
+ m_adverse_select_task_ptr->set_tasks({ "ChangeToAdverseDifficulty", "AdverseConfirm" });
+ m_subtasks.emplace_back(m_adverse_select_task_ptr);
+
auto start_1_tp = std::make_shared(callback, inst, TaskType);
start_1_tp->set_tasks({ "BattleStartPre" }).set_retry_times(0).set_ignore_error(true);
m_subtasks.emplace_back(start_1_tp);
- m_subtasks.emplace_back(m_formation_task_ptr);
+ m_subtasks.emplace_back(m_formation_task_ptr)->set_retry_times(0);
auto start_2_tp = std::make_shared(callback, inst, TaskType);
start_2_tp->set_tasks({ "BattleStartAll" }).set_ignore_error(false);
+ m_copilot_list_notification_ptr = start_2_tp->register_plugin();
m_subtasks.emplace_back(start_2_tp);
m_subtasks.emplace_back(m_battle_task_ptr)->set_retry_times(0);
- m_stop_task_ptr->set_tasks({ "ClickCornerUntilStartButton" });
m_stop_task_ptr->set_enable(false);
m_subtasks.emplace_back(m_stop_task_ptr);
}
@@ -56,10 +71,14 @@ bool asst::CopilotTask::set_params(const json::value& params)
Log.error("CopilotConfig parse failed");
return false;
}
+ m_task_file_reload_task_ptr->set_magic_code(match[1].str());
}
- else if (!Copilot.load(utils::path(*filename_opt))) {
- Log.error("CopilotConfig parse failed");
- return false;
+ else {
+ if (!Copilot.load(utils::path(*filename_opt))) {
+ Log.error("CopilotConfig parse failed");
+ return false;
+ }
+ m_task_file_reload_task_ptr->set_path(std::move(*filename_opt));
}
m_stage_name = Copilot.get_stage_name();
@@ -70,6 +89,8 @@ bool asst::CopilotTask::set_params(const json::value& params)
bool with_formation = params.get("formation", false);
m_formation_task_ptr->set_enable(with_formation);
+
+ // 自动补信赖
m_formation_task_ptr->set_add_trust(params.get("add_trust", false));
m_formation_task_ptr->set_add_user_additional(params.get("add_user_additional", false));
auto user_additional_opt = params.find("user_additional");
@@ -88,21 +109,46 @@ bool asst::CopilotTask::set_params(const json::value& params)
m_formation_task_ptr->set_user_additional(std::move(user_additional));
}
+ // 是否在当前页面左右滑动寻找关卡
+ // 启用队列的话,这项为true
+ bool need_navigate = params.get("need_navigate", false);
+ m_task_file_reload_task_ptr->set_enable(need_navigate);
+
+ // 不使用代理指挥
+ m_not_use_prts_task_ptr->set_enable(need_navigate && with_formation);
+ m_not_use_prts_task_ptr->set_tasks({ "NotUsePrts", "Stop" });
+
+ bool is_adverse = params.get("is_adverse", false);
+ m_adverse_select_task_ptr->set_enable(need_navigate && is_adverse);
+
+ // 防止在关卡名展开的情况下无法滑动,调整滑动区域
+ std::string m_navigate_name = params.get("navigate_name", std::string());
+ Task.get(m_navigate_name + "@Copilot@ClickStageName")->text = { m_navigate_name };
+ Task.get(m_navigate_name + "@Copilot@ClickedCorrectStage")->text = { m_navigate_name };
+ Task.get(m_navigate_name + "@Copilot@FullStageNavigation")->specific_rect = Rect(600, 100, 20, 20);
+ m_navigate_task_ptr->set_tasks({ m_navigate_name + "@Copilot@StageNavigationBegin" });
+ m_navigate_task_ptr->set_enable(need_navigate);
+
std::string support_unit_name = params.get("support_unit_name", std::string());
m_formation_task_ptr->set_support_unit_name(std::move(support_unit_name));
size_t loop_times = params.get("loop_times", 1);
if (loop_times > 1) {
+ m_stop_task_ptr->set_tasks({ "ClickCornerUntilStartButton" });
+ m_stop_task_ptr->set_enable(true);
+
+ // 追加
m_subtasks.reserve(m_subtasks.size() * loop_times);
auto raw_end = m_subtasks.end();
for (size_t i = 1; i < loop_times; ++i) {
// FIXME: 如果多次调用 set_params,这里复制的会有问题
m_subtasks.insert(m_subtasks.end(), m_subtasks.begin(), raw_end);
}
- m_stop_task_ptr->set_enable(true);
}
- else {
- m_stop_task_ptr->set_enable(false);
+ else if (need_navigate) {
+ Task.get("Copilot@BattleStartPreFlag")->text.emplace_back(m_navigate_name);
+ m_stop_task_ptr->set_tasks({ "Copilot@ClickCornerUntilStartButton" });
+ m_stop_task_ptr->set_enable(true);
}
return true;
diff --git a/src/MaaCore/Task/Interface/CopilotTask.h b/src/MaaCore/Task/Interface/CopilotTask.h
index 323fcb9a46..d7335e55c3 100644
--- a/src/MaaCore/Task/Interface/CopilotTask.h
+++ b/src/MaaCore/Task/Interface/CopilotTask.h
@@ -5,8 +5,10 @@
namespace asst
{
+ class TaskFileReloadTask;
class BattleProcessTask;
class BattleFormationTask;
+ class CopilotListNotificationPlugin;
class ProcessTask;
// 抄作业任务
@@ -22,8 +24,13 @@ namespace asst
std::string get_stage_name() const { return m_stage_name; }
private:
+ std::shared_ptr m_task_file_reload_task_ptr = nullptr;
+ std::shared_ptr m_navigate_task_ptr = nullptr;
+ std::shared_ptr m_not_use_prts_task_ptr = nullptr;
+ std::shared_ptr m_adverse_select_task_ptr = nullptr;
std::shared_ptr m_formation_task_ptr = nullptr;
std::shared_ptr m_battle_task_ptr = nullptr;
+ std::shared_ptr m_copilot_list_notification_ptr = nullptr;
std::shared_ptr m_stop_task_ptr = nullptr;
std::string m_stage_name;
};
diff --git a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h
index 26ea9d1c88..ca3b07a307 100644
--- a/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h
+++ b/src/MaaCore/Task/Miscellaneous/BattleFormationTask.h
@@ -25,8 +25,11 @@ namespace asst
void append_additional_formation(AdditionalFormation formation);
void set_support_unit_name(std::string name);
+ // 是否追加自定干员
void set_add_user_additional(bool add_user_additional);
+ // 设置追加自定干员列表
void set_user_additional(std::vector> user_additional);
+ // 是否追加低信赖干员
void set_add_trust(bool add_trust);
enum class DataResource
@@ -45,7 +48,6 @@ namespace asst
bool add_additional();
// 补充刷信赖的干员,从最小的开始
bool add_trust_operators();
-
bool enter_selection_page();
bool select_opers_in_cur_page(std::vector& groups);
void swipe_page();
diff --git a/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.cpp b/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.cpp
new file mode 100644
index 0000000000..011f40381c
--- /dev/null
+++ b/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.cpp
@@ -0,0 +1,24 @@
+#include "CopilotListNotificationPlugin.h"
+
+bool asst::CopilotListNotificationPlugin::verify(AsstMsg msg, const json::value& details) const
+{
+ if (msg != AsstMsg::SubTaskStart || details.get("subtask", std::string()) != "ProcessTask") {
+ return false;
+ }
+
+ const std::string task = details.at("details").at("task").as_string();
+ if (task != "BattleStartAll" && task.starts_with("BattleStart")) {
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+bool asst::CopilotListNotificationPlugin::_run()
+{
+ json::value info = basic_info_with_what("CopilotListEnterSuccess");
+ callback(AsstMsg::SubTaskExtraInfo, info);
+
+ return true;
+}
diff --git a/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.h b/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.h
new file mode 100644
index 0000000000..6c47221d00
--- /dev/null
+++ b/src/MaaCore/Task/Miscellaneous/CopilotListNotificationPlugin.h
@@ -0,0 +1,16 @@
+#pragma once
+#include "Task/AbstractTaskPlugin.h"
+
+namespace asst
+{
+ class CopilotListNotificationPlugin : public AbstractTaskPlugin
+ {
+ public:
+ using AbstractTaskPlugin::AbstractTaskPlugin;
+ virtual ~CopilotListNotificationPlugin() override = default;
+ virtual bool verify(AsstMsg msg, const json::value& details) const override;
+
+ private:
+ virtual bool _run() override;
+ };
+}
diff --git a/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.cpp b/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.cpp
new file mode 100644
index 0000000000..ee49794fbf
--- /dev/null
+++ b/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.cpp
@@ -0,0 +1,40 @@
+#include "TaskFileReloadTask.h"
+
+#include "Config/Miscellaneous/CopilotConfig.h"
+#include "Utils/Logger.hpp"
+
+void asst::TaskFileReloadTask::set_magic_code(std::string code)
+{
+ is_magic_code = true;
+ m_file = std::move(code);
+}
+
+void asst::TaskFileReloadTask::set_path(std::string path)
+{
+ is_path = true;
+ m_file = std::move(path);
+}
+
+bool asst::TaskFileReloadTask::_run()
+{
+ if (is_magic_code) {
+ if (!Copilot.parse_magic_code(m_file)) {
+ Log.error("CopilotConfig parse failed");
+ return false;
+ }
+ }
+ else if (is_path) {
+ if (!Copilot.load(utils::path(m_file))) {
+ Log.error("CopilotConfig parse failed");
+ return false;
+ }
+ }
+ else {
+ return false;
+ }
+
+ json::value info = basic_info_with_what("CopilotListLoadTaskFileSuccess");
+ info["details"]["stage_name"] = Copilot.get_stage_name();
+ callback(AsstMsg::SubTaskExtraInfo, info);
+ return true;
+}
diff --git a/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.h b/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.h
new file mode 100644
index 0000000000..695f536451
--- /dev/null
+++ b/src/MaaCore/Task/Miscellaneous/TaskFileReloadTask.h
@@ -0,0 +1,19 @@
+#pragma once
+#include "Task/AbstractTaskPlugin.h"
+
+namespace asst
+{
+ class TaskFileReloadTask : public AbstractTask
+ {
+ public:
+ using AbstractTask::AbstractTask;
+ virtual ~TaskFileReloadTask() override = default;
+ void set_magic_code(std::string code);
+ void set_path(std::string path);
+
+ private:
+ virtual bool _run() override;
+ std::string m_file;
+ bool is_path = false, is_magic_code = false;
+ };
+}
diff --git a/src/MaaWpfGui/Constants/ConfigurationKeys.cs b/src/MaaWpfGui/Constants/ConfigurationKeys.cs
index 4e77ed7760..64def5a771 100644
--- a/src/MaaWpfGui/Constants/ConfigurationKeys.cs
+++ b/src/MaaWpfGui/Constants/ConfigurationKeys.cs
@@ -127,6 +127,7 @@ namespace MaaWpfGui.Constants
public const string CopilotAddUserAdditional = "Copilot.AddUserAdditional";
public const string CopilotUserAdditional = "Copilot.UserAdditional";
public const string CopilotLoopTimes = "Copilot.LoopTimes";
+ public const string CopilotTaskList = "Copilot.CopilotTaskList";
public const string UpdateProxy = "VersionUpdate.Proxy";
public const string VersionType = "VersionUpdate.VersionType";
diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs
index db8e830004..a4dbcfb686 100644
--- a/src/MaaWpfGui/Main/AsstProxy.cs
+++ b/src/MaaWpfGui/Main/AsstProxy.cs
@@ -15,15 +15,14 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
-using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using HandyControl.Data;
-using HandyControl.Tools.Extension;
using MaaWpfGui.Constants;
using MaaWpfGui.Extensions;
using MaaWpfGui.Helper;
@@ -573,7 +572,11 @@ namespace MaaWpfGui.Main
Instances.TaskQueueViewModel.AddLog(LocalizationHelper.GetString("CompleteTask") + taskChain);
if (isCoplitTaskChain)
{
- runningState.SetIdle(true);
+ if (!Instances.CopilotViewModel.UseCopilotList || Instances.CopilotViewModel.CopilotItemViewModels.All(model => !model.IsChecked))
+ {
+ runningState.SetIdle(true);
+ }
+
Instances.CopilotViewModel.AddLog(LocalizationHelper.GetString("CompleteCombat"), UiLogColor.Info);
}
@@ -1058,6 +1061,12 @@ namespace MaaWpfGui.Main
}
break;
+ case "CopilotListLoadTaskFileSuccess":
+ Instances.CopilotViewModel.AddLog("Parse " + subTaskDetails["stage_name"].ToString() + " Success");
+ break;
+ case "CopilotListEnterSuccess":
+ Instances.CopilotViewModel.EnterCopilotTask();
+ break;
case "SSSStage":
{
@@ -1832,35 +1841,37 @@ namespace MaaWpfGui.Main
/// 是否追加信赖干员
/// 是否追加自定干员
/// 自定干员列表
+ /// 是否导航至关卡(启用自动战斗序列)
+ /// 关卡名
+ /// 是不是突袭
/// 任务类型
/// 任务重复执行次数
+ /// 是否启动战斗
/// 是否成功。
- public bool AsstStartCopilot(string filename, bool formation, bool add_trust, bool add_user_additional, string user_additional, string type, int loop_times)
+ public bool AsstStartCopilot(string filename, bool formation, bool add_trust, bool add_user_additional, JArray user_additional, bool need_navigate, string navigate_name, bool is_adverse, string type, int loop_times, bool asst_start = true)
{
- JArray m_user_additional = new JArray();
- Regex regex = new Regex(@"(?<=;)(?[^,;]+)(?:, *(?\d))? *", RegexOptions.Compiled);
- MatchCollection matches = regex.Matches(";" + user_additional);
- foreach (Match match in matches)
- {
- m_user_additional.Add(new JObject
- {
- ["name"] = match.Groups[1].Value.Trim(),
- ["skill"] = match.Groups[2].Value.IsNullOrEmpty() ? 0 : int.Parse(match.Groups[2].Value),
- });
- }
-
var task_params = new JObject
{
["filename"] = filename,
["formation"] = formation,
["add_trust"] = add_trust,
["add_user_additional"] = add_user_additional,
- ["user_additional"] = m_user_additional,
+ ["user_additional"] = user_additional,
+ ["need_navigate"] = need_navigate,
+ ["navigate_name"] = navigate_name,
+ ["is_adverse"] = is_adverse,
["loop_times"] = loop_times,
};
AsstTaskId id = AsstAppendTaskWithEncoding(type, task_params);
_latestTaskId[TaskType.Copilot] = id;
- return id != 0 && AsstStart();
+ if (asst_start)
+ {
+ return id != 0 && AsstStart();
+ }
+ else
+ {
+ return id != 0;
+ }
}
public bool AsstStartVideoRec(string filename)
diff --git a/src/MaaWpfGui/Res/Localizations/en-us.xaml b/src/MaaWpfGui/Res/Localizations/en-us.xaml
index c816728f6c..47412f8525 100644
--- a/src/MaaWpfGui/Res/Localizations/en-us.xaml
+++ b/src/MaaWpfGui/Res/Localizations/en-us.xaml
@@ -446,6 +446,8 @@ The video aspect ratio needs to be 16:9 without interference factors such as bla
Add low-trust operators
Add custom operators
Use ";" as the separator, "," to separate the operator name and skills, for example: W, 3; Ash, 2
+ Battle list (Please switch to the level selection page before starting)
+ Right click to add raid difficulty
Loop Times
Start
Video Link
diff --git a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml
index 10fb166a69..b6d39ad072 100644
--- a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml
+++ b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml
@@ -438,6 +438,8 @@ Bilibili: ログイン インターフェイスに表示されるアカウント
信頼性の低いオペレーターを追加する
カスタム戦術要員の追加
使用「;」オペレータ名とスキルを区切るには、区切り文字として「,」を使用します。例: W, 3; Ash, 2
+ バトルリスト(開始前にレベル選択ページに切り替えてください)
+ 右クリックしてレイドの難易度を追加します
ループ回数
開始
映像へのハイパーリンク
diff --git a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml
index d727e678da..7e9bd0f9ef 100644
--- a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml
+++ b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml
@@ -450,6 +450,8 @@ Bilibili: 로그인 인터페이스에 표시되는 계정 이름(예: Zhang San
신뢰도가 낮은 운영자 추가
맞춤 연산자 추가
사용 ";" 운영자 이름과 기술을 구분하기 위해 구분 기호 ","를 사용합니다. 예: W, 3; Ash, 2
+ 전투 목록(시작하기 전에 레벨 선택 페이지로 전환하세요)
+ 공격대 난이도를 추가하려면 마우스 오른쪽 버튼을 클릭하세요.
반복 횟수
시작
영상 링크
diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml
index 65075a6c86..6a8415acce 100644
--- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml
+++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml
@@ -468,6 +468,8 @@
追加自定干员
以英文";"为分隔符,英文","分隔干员名与技能,例: 史尔特尔,3;艾雅法拉,1
循环次数
+ 战斗列表 (开始前请切换至关卡选择页面)
+ 右键添加突袭难度
开始
视频链接
diff --git a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml
index ecff9cc6ed..2eaf730d22 100644
--- a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml
+++ b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml
@@ -448,6 +448,8 @@
補充低信賴幹員
追加自定幹員
使用";"作為分隔符,用","分隔操作員姓名和技能,例:史尔特尔,3;艾雅法拉,1
+ 戰鬥列表 (開始前請切換至關卡選擇頁面)
+ 右鍵添加突襲難度
循環次數
開始
影片連結
diff --git a/src/MaaWpfGui/ViewModels/CopilotItemViewModel.cs b/src/MaaWpfGui/ViewModels/CopilotItemViewModel.cs
new file mode 100644
index 0000000000..8c974070e3
--- /dev/null
+++ b/src/MaaWpfGui/ViewModels/CopilotItemViewModel.cs
@@ -0,0 +1,104 @@
+using System.Security.RightsManagement;
+using Stylet;
+using Vanara.PInvoke;
+
+namespace MaaWpfGui.ViewModels
+{
+ public class CopilotItemViewModel : PropertyChangedBase
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name.
+ /// The original Name of file
+ public CopilotItemViewModel(string name, string filePath)
+ {
+ Name = name;
+ FilePath = filePath;
+ IsChecked = true;
+ }
+
+ private string _filePath;
+
+ ///
+ /// Gets or sets the original_name.
+ ///
+ public string FilePath
+ {
+ get => _filePath;
+ set => SetAndNotify(ref _filePath, value);
+ }
+
+ private string _name;
+
+ ///
+ /// Gets or sets the name.
+ ///
+ public string Name
+ {
+ get => _name;
+ set => SetAndNotify(ref _name, value);
+ }
+
+ private bool _isChecked;
+
+ ///
+ /// Gets or sets a value indicating whether gets or sets whether the key is checked.
+ ///
+ public bool IsChecked
+ {
+ get => _isChecked;
+ set
+ {
+ SetAndNotify(ref _isChecked, value);
+ }
+ }
+
+ // 换成图标的话要这个,暂时没用
+ private string _iconPath;
+
+ ///
+ /// Gets or sets the icon path.
+ ///
+ // ReSharper disable once UnusedMember.Global
+ public string IconPath
+ {
+ get => _iconPath;
+ set => SetAndNotify(ref _iconPath, value);
+ }
+
+ private string _token;
+
+ ///
+ /// Gets or sets the token.
+ ///
+ // ReSharper disable once UnusedMember.Global
+ public string Token
+ {
+ get => _token;
+ set => SetAndNotify(ref _token, value);
+ }
+
+ private string _runStatus;
+
+ ///
+ /// Gets or sets the running status.
+ ///
+ // ReSharper disable once UnusedMember.Global
+ public string RunStatus
+ {
+ get => _runStatus;
+ set => SetAndNotify(ref _runStatus, value);
+ }
+
+ private int _index = 0;
+
+ public int Index
+ {
+ get => _index;
+ set => SetAndNotify(ref _index, value);
+ }
+
+ public int GetIndex() => Index;
+ }
+}
diff --git a/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs b/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs
index c03cfd9bd8..2a01e55948 100644
--- a/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs
+++ b/src/MaaWpfGui/ViewModels/UI/CopilotViewModel.cs
@@ -21,14 +21,17 @@ using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
+using HandyControl.Tools.Extension;
using MaaWpfGui.Constants;
using MaaWpfGui.Helper;
using MaaWpfGui.States;
using Microsoft.Win32;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using Serilog;
using Stylet;
using DataFormats = System.Windows.Forms.DataFormats;
+using Task = System.Threading.Tasks.Task;
namespace MaaWpfGui.ViewModels.UI
{
@@ -46,6 +49,11 @@ namespace MaaWpfGui.ViewModels.UI
///
public ObservableCollection LogItemViewModels { get; }
+ ///
+ /// Gets or private sets the view models of Copilot items.
+ ///
+ public ObservableCollection CopilotItemViewModels { get; private set; } = new ObservableCollection();
+
///
/// Initializes a new instance of the class.
///
@@ -56,6 +64,21 @@ namespace MaaWpfGui.ViewModels.UI
AddLog(LocalizationHelper.GetString("CopilotTip"));
_runningState = RunningState.Instance;
_runningState.IdleChanged += RunningState_IdleChanged;
+
+ var copilotTaskList = ConfigurationHelper.GetValue(ConfigurationKeys.CopilotTaskList, string.Empty);
+ if (!string.IsNullOrEmpty(copilotTaskList))
+ {
+ JArray jArray = JArray.Parse(copilotTaskList);
+ foreach (var item in jArray)
+ {
+ if ((item as JObject).TryGetValue("file_path", out var token) && File.Exists(token.ToString()))
+ {
+ CopilotItemViewModels.Add(new CopilotItemViewModel((string)item["name"], (string)item["file_path"]) { IsChecked = (bool)item["is_checked"] });
+ }
+ }
+
+ CopilotItemIndexChanged();
+ }
}
private void RunningState_IdleChanged(object sender, bool e)
@@ -236,6 +259,14 @@ namespace MaaWpfGui.ViewModels.UI
if (doc != null && doc.TryGetValue("title", out var titleValue))
{
title = titleValue.ToString();
+
+ // 为自动作战列表匹配名字
+ var linkParser = new Regex(@"([a-z]{0,3})(\d{0,2})-(EX-)?(\d{1,2})", RegexOptions.Compiled | RegexOptions.IgnoreCase);
+ foreach (Match match in linkParser.Matches(title))
+ {
+ CopilotTaskName = match.Value;
+ break;
+ }
}
if (title.Length != 0)
@@ -503,6 +534,144 @@ namespace MaaWpfGui.ViewModels.UI
}
}
+ ///
+ /// Gets or sets a value indicating whether to use auto-formation.
+ ///
+ private bool _useCopilotList = false;
+
+ public bool UseCopilotList
+ {
+ get => _useCopilotList;
+ set
+ {
+ SetAndNotify(ref _useCopilotList, value);
+ }
+ }
+
+ ///
+ /// Gets or sets a value indicating whether to use auto-formation.
+ ///
+ private string _copilotTaskName = string.Empty;
+
+ public string CopilotTaskName
+ {
+ get => _copilotTaskName;
+ set
+ {
+ SetAndNotify(ref _copilotTaskName, value);
+ }
+ }
+
+ private static string copilotJsonDir = "cache/copilot";
+
+ public void AddCopilotTask()
+ {
+ var stage_name = CopilotTaskName.Trim().Replace("突袭", "-Adverse");
+ if (!stage_name.IsNullOrEmpty())
+ {
+ AddCopilotTaskToList(stage_name);
+ }
+ }
+
+ public void AddCopilotTask_Adverse()
+ {
+ var stage_name = CopilotTaskName.Trim().Replace("突袭", "-Adverse");
+ if (!stage_name.EndsWith("-Adverse"))
+ {
+ stage_name += "-Adverse";
+ }
+
+ if (!stage_name.IsNullOrEmpty())
+ {
+ AddCopilotTaskToList(stage_name);
+ }
+ }
+
+ public void AddCopilotTaskToList(string stage_name)
+ {
+ var jsonPath = $"{copilotJsonDir}/{stage_name}.json";
+
+ try
+ {
+ Directory.CreateDirectory(copilotJsonDir);
+ }
+ catch
+ {
+ }
+
+ try
+ {
+ File.Copy(IsDataFromWeb ? TempCopilotFile : Filename, jsonPath, true);
+ var item = new CopilotItemViewModel(stage_name, jsonPath)
+ {
+ Index = CopilotItemViewModels.Count,
+ };
+ CopilotItemViewModels.Add(item);
+ SaveCopilotTask();
+ }
+ catch (Exception ex)
+ {
+ AddLog(LocalizationHelper.GetString("CopilotJsonError"), UiLogColor.Error);
+ Log.Error(ex.ToString());
+ }
+ }
+
+ public void SaveCopilotTask()
+ {
+ JArray jArray = new JArray(CopilotItemViewModels.Select(item => new JObject
+ {
+ ["name"] = item.Name,
+ ["file_path"] = item.FilePath,
+ ["is_checked"] = item.IsChecked,
+ }).ToArray());
+ ConfigurationHelper.SetValue(ConfigurationKeys.CopilotTaskList, JsonConvert.SerializeObject(jArray));
+ }
+
+ public void DeleteCopilotTask(int index)
+ {
+ CopilotItemViewModels.RemoveAt(index);
+ CopilotItemIndexChanged();
+ }
+
+ public void ClearCopilotTask()
+ {
+ CopilotItemViewModels.Clear();
+ SaveCopilotTask();
+ }
+
+ public void EnterCopilotTask()
+ {
+ Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ for (int i = 0; i < CopilotItemViewModels.Count; i++)
+ {
+ if (CopilotItemViewModels[i].IsChecked)
+ {
+ CopilotItemViewModels[i].IsChecked = false;
+ break;
+ }
+ }
+
+ SaveCopilotTask();
+ });
+ }
+
+ ///
+ /// 更新任务顺序
+ ///
+ public void CopilotItemIndexChanged()
+ {
+ Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ for (int i = 0; i < CopilotItemViewModels.Count; i++)
+ {
+ CopilotItemViewModels[i].Index = i;
+ }
+
+ SaveCopilotTask();
+ });
+ }
+
public bool Loop { get; set; }
private int _loopTimes = int.Parse(ConfigurationHelper.GetValue(ConfigurationKeys.CopilotLoopTimes, "1"));
@@ -558,14 +727,51 @@ namespace MaaWpfGui.ViewModels.UI
AddLog(errMsg, UiLogColor.Error);
}
- bool ret = Instances.AsstProxy.AsstStartCopilot(IsDataFromWeb ? TempCopilotFile : Filename, Form, AddTrust, AddUserAdditional, UserAdditional, _taskType,
- Loop ? LoopTimes : 1);
+ JArray mUserAdditional = new JArray();
+ Regex regex = new Regex(@"(?<=;)(?[^,;]+)(?:, *(?\d))? *", RegexOptions.Compiled);
+ MatchCollection matches = regex.Matches(";" + UserAdditional);
+ foreach (Match match in matches)
+ {
+ mUserAdditional.Add(new JObject
+ {
+ ["name"] = match.Groups[1].Value.Trim(),
+ ["skill"] = match.Groups[2].Value.IsNullOrEmpty() ? 0 : int.Parse(match.Groups[2].Value),
+ });
+ }
+
+ bool ret = true;
+ if (UseCopilotList)
+ {
+ bool startAny = false;
+ foreach (var model in CopilotItemViewModels)
+ {
+ if (model.IsChecked)
+ {
+ ret &= Instances.AsstProxy.AsstStartCopilot(model.FilePath, Form, AddTrust, AddUserAdditional, mUserAdditional, UseCopilotList, model.Name.Replace("-Adverse", string.Empty), model.Name.Contains("-Adverse"), _taskType, Loop ? LoopTimes : 1, false);
+ startAny = true;
+ }
+ }
+
+ // 一个都没启动,怎会有如此无聊之人
+ if (!startAny)
+ {
+ return;
+ }
+
+ ret &= Instances.AsstProxy.AsstStart();
+ }
+ else
+ {
+ ret &= Instances.AsstProxy.AsstStartCopilot(IsDataFromWeb ? TempCopilotFile : Filename, Form, AddTrust, AddUserAdditional, mUserAdditional, UseCopilotList, string.Empty, false, _taskType, Loop ? LoopTimes : 1);
+ }
+
if (ret)
{
AddLog(LocalizationHelper.GetString("Running"));
}
else
{
+ Instances.AsstProxy.AsstStop();
_runningState.SetIdle(true);
AddLog(LocalizationHelper.GetString("CopilotFileReadError"), UiLogColor.Error);
}
diff --git a/src/MaaWpfGui/Views/UI/CopilotView.xaml b/src/MaaWpfGui/Views/UI/CopilotView.xaml
index 759b6674f7..464c955535 100644
--- a/src/MaaWpfGui/Views/UI/CopilotView.xaml
+++ b/src/MaaWpfGui/Views/UI/CopilotView.xaml
@@ -6,6 +6,7 @@
xmlns:constants="clr-namespace:MaaWpfGui.Constants"
xmlns:controls="clr-namespace:MaaWpfGui.Styles.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:dd="urn:gong-wpf-dragdrop"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:helper="clr-namespace:MaaWpfGui.Helper"
xmlns:local="clr-namespace:MaaWpfGui"
@@ -31,7 +32,7 @@
@@ -62,90 +63,22 @@
Style="{StaticResource ButtonDefault}"
ToolTip="{DynamicResource PasteClipboardTip}" />
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+