feat: 自动战斗新增战斗列表选项(异形UI不支持) (#6350)

This commit is contained in:
MistEO
2023-09-17 01:59:51 +08:00
committed by GitHub
23 changed files with 874 additions and 121 deletions

View File

@@ -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",
@@ -7022,6 +7043,12 @@
"Stop"
]
},
"BattleQuickFormationCheck": {
"baseTask": "BattleQuickFormation",
"template": "BattleQuickFormation.png",
"action": "DoNothing",
"next": []
},
"BattleQuickFormation": {
"action": "ClickSelf",
"roi": [
@@ -13080,6 +13107,45 @@
163
]
},
"Copilot@ClickCornerUntilFailedOrStartButton": {
"algorithm": "JustReturn",
"action": "DoNothing",
"next": [
"Copilot@MissionFailed",
"Copilot@BattleStartPreFlag",
"Copilot@ClickCornerUntilStartButton"
]
},
"Copilot@ClickCornerUntilStartButton": {
"next": [
"Copilot@ClickCornerUntilFailedOrStartButton"
]
},
"Copilot@MissionFailed": {
"Doc": "如果没有三星就终止",
"template": "MissionFailed.png",
"action": "DoNothing",
"roi": [
210,
290,
70,
70
],
"next_Doc": "主动抛错",
"next": [
"Copilot@BattleStartPreFlag"
]
},
"Copilot@BattleStartPreFlag": {
"baseTask": "BattleStartPre",
"action": "DoNothing",
"roi":[
0,
0,
1280,
720
]
},
"ClickCornerUntilStartButton": {
"algorithm": "JustReturn",
"action": "ClickRect",

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -73,8 +73,10 @@
<ClInclude Include="Task\Interface\CustomTask.h" />
<ClInclude Include="Task\Interface\VideoRecognitionTask.h" />
<ClInclude Include="Task\Interface\OperBoxTask.h" />
<ClInclude Include="Task\Miscellaneous\CopilotListNotificationPlugin.h" />
<ClInclude Include="Task\Miscellaneous\OperBoxRecognitionTask.h" />
<ClInclude Include="Task\Miscellaneous\AccountSwitchTask.h" />
<ClInclude Include="Task\Miscellaneous\TaskFileReloadTask.h" />
<ClInclude Include="Task\Reclamation\ReclamationControlTask.h" />
<ClInclude Include="Task\Reclamation\ReclamationConclusionReportPlugin.h" />
<ClInclude Include="Task\Reclamation\ReclamationBattlePlugin.h" />
@@ -234,8 +236,10 @@
<ClCompile Include="Task\Infrast\InfrastProcessingTask.cpp" />
<ClCompile Include="Task\Interface\VideoRecognitionTask.cpp" />
<ClCompile Include="Task\Interface\OperBoxTask.cpp" />
<ClCompile Include="Task\Miscellaneous\CopilotListNotificationPlugin.cpp" />
<ClCompile Include="Task\Miscellaneous\OperBoxRecognitionTask.cpp" />
<ClCompile Include="Task\Miscellaneous\AccountSwitchTask.cpp" />
<ClCompile Include="Task\Miscellaneous\TaskFileReloadTask.cpp" />
<ClCompile Include="Task\Reclamation\ReclamationControlTask.cpp" />
<ClCompile Include="Task\Reclamation\ReclamationConclusionReportPlugin.cpp" />
<ClCompile Include="Task\Reclamation\ReclamationBattlePlugin.cpp" />

View File

@@ -633,6 +633,12 @@
<ClInclude Include="Task\Infrast\InfrastProcessingTask.h">
<Filter>源文件\Task\Infrast</Filter>
</ClInclude>
<ClInclude Include="Task\Miscellaneous\CopilotListNotificationPlugin.h">
<Filter>源文件\Task\Miscellaneous</Filter>
</ClInclude>
<ClInclude Include="Task\Miscellaneous\TaskFileReloadTask.h">
<Filter>源文件\Task\Miscellaneous</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Vision\VisionHelper.cpp">
@@ -1049,5 +1055,11 @@
<ClCompile Include="Task\Infrast\InfrastProcessingTask.cpp">
<Filter>源文件\Task\Infrast</Filter>
</ClCompile>
<ClCompile Include="Task\Miscellaneous\CopilotListNotificationPlugin.cpp">
<Filter>源文件\Task\Miscellaneous</Filter>
</ClCompile>
<ClCompile Include="Task\Miscellaneous\TaskFileReloadTask.cpp">
<Filter>源文件\Task\Miscellaneous</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -3,33 +3,48 @@
#include <regex>
#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<TaskFileReloadTask>(callback, inst, TaskType)),
m_navigate_task_ptr(std::make_shared<ProcessTask>(callback, inst, TaskType)),
m_not_use_prts_task_ptr(std::make_shared<ProcessTask>(callback, inst, TaskType)),
m_adverse_select_task_ptr(std::make_shared<ProcessTask>(callback, inst, TaskType)),
m_formation_task_ptr(std::make_shared<BattleFormationTask>(callback, inst, TaskType)),
m_battle_task_ptr(std::make_shared<BattleProcessTask>(callback, inst, TaskType)),
m_stop_task_ptr(std::make_shared<ProcessTask>(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<ProcessTask>(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<ProcessTask>(callback, inst, TaskType);
start_2_tp->set_tasks({ "BattleStartAll" }).set_ignore_error(false);
m_copilot_list_notification_ptr = start_2_tp->register_plugin<CopilotListNotificationPlugin>();
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<json::array>("user_additional");
@@ -88,21 +109,47 @@ 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);
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<OcrTaskInfo>(m_navigate_name + "@Copilot@ClickStageName")->text = { m_navigate_name };
Task.get<OcrTaskInfo>(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<OcrTaskInfo>("Copilot@BattleStartPreFlag")->text.emplace_back(m_navigate_name);
m_stop_task_ptr->set_tasks({ "Copilot@ClickCornerUntilFailedOrStartButton" });
m_stop_task_ptr->set_enable(true);
}
return true;

View File

@@ -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<TaskFileReloadTask> m_task_file_reload_task_ptr = nullptr;
std::shared_ptr<ProcessTask> m_navigate_task_ptr = nullptr;
std::shared_ptr<ProcessTask> m_not_use_prts_task_ptr = nullptr;
std::shared_ptr<ProcessTask> m_adverse_select_task_ptr = nullptr;
std::shared_ptr<BattleFormationTask> m_formation_task_ptr = nullptr;
std::shared_ptr<BattleProcessTask> m_battle_task_ptr = nullptr;
std::shared_ptr<CopilotListNotificationPlugin> m_copilot_list_notification_ptr = nullptr;
std::shared_ptr<ProcessTask> m_stop_task_ptr = nullptr;
std::string m_stage_name;
};

View File

@@ -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<std::pair<std::string, int>> 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<OperGroup>& groups);
void swipe_page();

View File

@@ -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;
}

View File

@@ -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;
};
}

View File

@@ -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;
}

View File

@@ -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;
};
}

View File

@@ -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";

View File

@@ -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;
@@ -531,6 +530,7 @@ namespace MaaWpfGui.Main
toast.Show();
if (isCoplitTaskChain)
{
AsstStop();
runningState.SetIdle(true);
Instances.CopilotViewModel.AddLog(LocalizationHelper.GetString("CombatError"), UiLogColor.Error);
}
@@ -573,7 +573,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 +1062,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 +1842,37 @@ namespace MaaWpfGui.Main
/// <param name="add_trust">是否追加信赖干员</param>
/// <param name="add_user_additional">是否追加自定干员</param>
/// <param name="user_additional">自定干员列表</param>
/// <param name="need_navigate">是否导航至关卡(启用自动战斗序列)</param>
/// <param name="navigate_name">关卡名</param>
/// <param name="is_adverse">是不是突袭</param>
/// <param name="type">任务类型</param>
/// <param name="loop_times">任务重复执行次数</param>
/// <param name="asst_start">是否启动战斗</param>
/// <returns>是否成功。</returns>
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(@"(?<=;)(?<name>[^,;]+)(?:, *(?<skill>\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)

View File

@@ -446,6 +446,10 @@ The video aspect ratio needs to be 16:9 without interference factors such as bla
<system:String x:Key="AddTrust">Add low-trust operators</system:String>
<system:String x:Key="AddUserAdditional">Add custom operators</system:String>
<system:String x:Key="AddUserAdditionalTip">Use ";" as the separator, "," to separate the operator name and skills, for example: W, 3; Ash, 2</system:String>
<system:String x:Key="UseCopilotList">Battle list</system:String>
<system:String x:Key="UseCopilotListTip">Please switch to the level selection page before starting</system:String>
<system:String x:Key="CopilotAddTask">Right click to add raid difficulty</system:String>
<system:String x:Key="CopilotClearTask">Right click to clear inactive tasks</system:String>
<system:String x:Key="LoopTimes">Loop Times</system:String>
<system:String x:Key="Start">Start</system:String>
<system:String x:Key="VideoLink">Video Link</system:String>
@@ -459,6 +463,12 @@ The video aspect ratio needs to be 16:9 without interference factors such as bla
Please start on the 「Start Deployment」 screen after manual formation (can be used with 「Loop Times」)\n\n
5. Video recognition is now supported, please drag the strategy video to use.\n
The video aspect ratio needs to be 16:9 without interference factors such as black borders, emulator borders special shapes and screen corrections.\n\n
6. Battle list:\n
After selecting the job, check that the level name below the list is correct (eg: CV-EX-1). \n
Add: Left click to add normal difficulty, right click to add raid difficulty. \n
Clear: Left click to clear the list, right click to remove only inactive tasks. \n
Before starting, you need to switch to the level selection interface. Cross-chapter navigation is not supported. \n
The operation will be terminated when encountering insufficient sanity, losing the battle, or failing to settle with three stars. \n\n
</system:String>
<system:String x:Key="CopilotFileReadError">Failed to read file!</system:String>
<system:String x:Key="CopilotNoFound">No corresponding file found!</system:String>

View File

@@ -438,6 +438,10 @@ Bilibili: ログイン インターフェイスに表示されるアカウント
<system:String x:Key="AddTrust">信頼性の低いオペレーターを追加する</system:String>
<system:String x:Key="AddUserAdditional">カスタム戦術要員の追加</system:String>
<system:String x:Key="AddUserAdditionalTip">使用「;」オペレータ名とスキルを区切るには、区切り文字として「,」を使用します。例: W, 3; Ash, 2</system:String>
<system:String x:Key="UseCopilotList">バトルリスト</system:String>
<system:String x:Key="UseCopilotListTip">開始前にレベル選択ページに切り替えてください</system:String>
<system:String x:Key="CopilotAddTask">右クリックしてレイドの難易度を追加します</system:String>
<system:String x:Key="CopilotClearTask">右クリックして非アクティブなタスクをクリアします</system:String>
<system:String x:Key="LoopTimes">ループ回数</system:String>
<system:String x:Key="Start">開始</system:String>
<system:String x:Key="VideoLink">映像へのハイパーリンク</system:String>
@@ -451,6 +455,12 @@ Bilibili: ログイン インターフェイスに表示されるアカウント
手動形成後、「開始デプロイメント」画面から開始してください(「ループ回数」で使用可能)。\n\n
5. ビデオ認識もサポートされており、ガイドビデオをドラッグして使用できます。\n
ビデオ解像度は16:9必須。黒枠、エミュレーター枠、特殊な形状、画面効果などが無いことを確認してください。\n\n
6. バトルリスト:\n
ジョブを選択した後、リストの下のレベル名が正しいことを確認してください (例: CV-EX-1)。 \n
追加: 左クリックしてノーマル難易度を追加し、右クリックしてレイド難易度を追加します。\n
クリア: 左クリックするとリストがクリアされ、右クリックすると非アクティブなタスクのみが削除されます。\n
開始する前に、レベル選択インターフェースに切り替える必要があります。章間のナビゲーションはサポートされていません。\n
正気度が不十分な場合、戦闘が失敗した場合、または 3 つ星を解決できない場合、アクションは終了します。 \n\n
</system:String>
<system:String x:Key="CopilotFileReadError">ファイルの読み取りに失敗しました!</system:String>
<system:String x:Key="CopilotNoFound">対応する攻略ファイルが見つかりません!</system:String>

View File

@@ -448,6 +448,10 @@ Bilibili: 로그인 인터페이스에 표시되는 계정 이름(예: Zhang San
<system:String x:Key="AddTrust">신뢰도가 낮은 운영자 추가</system:String>
<system:String x:Key="AddUserAdditional">맞춤 연산자 추가</system:String>
<system:String x:Key="AddUserAdditionalTip">사용 ";" 운영자 이름과 기술을 구분하기 위해 구분 기호 ","를 사용합니다. 예: W, 3; Ash, 2</system:String>
<system:String x:Key="UseCopilotList">전투 목록</system:String>
<system:String x:Key="UseCopilotListTip">시작하기 전에 레벨 선택 페이지로 전환하세요</system:String>
<system:String x:Key="CopilotAddTask">공격대 난이도를 추가하려면 마우스 오른쪽 버튼을 클릭하세요.</system:String>
<system:String x:Key="CopilotClearTask">비활성 작업을 지우려면 마우스 오른쪽 버튼을 클릭하세요.</system:String>
<system:String x:Key="LoopTimes">반복 횟수</system:String>
<system:String x:Key="Start">시작</system:String>
<system:String x:Key="VideoLink">영상 링크</system:String>
@@ -461,6 +465,12 @@ Bilibili: 로그인 인터페이스에 표시되는 계정 이름(예: Zhang San
수동 편성 후 '작전 개시' 버튼이 있는 화면에서 시작하세요. ('반복 횟수'와 함께 사용 가능)\n\n
5. 동영상 인식이 지원되며, 가이드 동영상를 드래그하여 사용할 수 있습니다.\n
동영상의 해상도는 16:9여야 하며, 검은색 테두리, 에뮬레이터 테두리, 특수한 모양의 화면 보정 등의 방해 요소가 없어야 합니다.\n\n
6. 전투 목록:\n
작업을 선택한 후 목록 아래의 레벨 이름이 올바른지 확인하세요(예: CV-EX-1). \n
추가: 일반 난이도를 추가하려면 마우스 왼쪽 버튼을 클릭하고, 레이드 난이도를 추가하려면 마우스 오른쪽 버튼을 클릭하세요. \n
지우기: 목록을 지우려면 마우스 왼쪽 버튼을 클릭하고, 비활성 작업만 제거하려면 마우스 오른쪽 버튼을 클릭합니다. \n
시작하기 전에 레벨 선택 인터페이스로 전환해야 합니다. 크로스 챕터 탐색은 지원되지 않습니다. \n
정신력이 부족하거나, 전투가 실패하거나, 별 3개를 해결할 수 없는 경우 액션이 종료됩니다. \n\n
</system:String>
<system:String x:Key="CopilotFileReadError">파일을 읽지 못했습니다!</system:String>
<system:String x:Key="CopilotNoFound">해당 파일을 찾을 수 없습니다!</system:String>

View File

@@ -468,6 +468,10 @@
<system:String x:Key="AddUserAdditional">追加自定干员</system:String>
<system:String x:Key="AddUserAdditionalTip">以英文";"为分隔符,英文","分隔干员名与技能,例: 史尔特尔,3;艾雅法拉,1</system:String>
<system:String x:Key="LoopTimes">循环次数</system:String>
<system:String x:Key="UseCopilotList">战斗列表</system:String>
<system:String x:Key="UseCopilotListTip">开始前请切换至关卡选择页面</system:String>
<system:String x:Key="CopilotAddTask">右键添加突袭难度</system:String>
<system:String x:Key="CopilotClearTask">右键清除未激活任务</system:String>
<system:String x:Key="Start">开始</system:String>
<system:String x:Key="VideoLink">视频链接</system:String>
<!-- 日志 -->
@@ -480,6 +484,12 @@
请手动编队后在「开始部署」界面开始(可配合「循环次数」使用)\n\n
5. 现已支持视频识别,请将攻略视频文件拖入后开始。\n
需要视频分辨率为 16:9无黑边、模拟器边框、异形屏矫正等干扰元素\n\n
6. 战斗列表:\n
选择作业后,检查列表下方的关卡名是否正确(如: CV-EX-1。\n
添加: 左键添加正常难度,右键添加突袭难度。\n
清除: 左键清空列表,右键仅移除未激活的任务。\n
开始前,需要切换至对应关卡的选择界面,不支持跨章节导航。\n
遇到 理智不足、战斗失败、未能以三星结算 时将会中止运行。\n\n
</system:String>
<system:String x:Key="CopilotFileReadError">读取文件失败!</system:String>
<system:String x:Key="CopilotNoFound">未找到对应作业!</system:String>
@@ -645,11 +655,11 @@
<system:String x:Key="GameResourceUpdated">游戏资源已更新,请重启 MAA</system:String>
<system:String x:Key="GameResourceUpdating">正在更新游戏资源,请耐心等待</system:String>
<!-- Api -->
<!-- External Notification -->
<!-- External Notification -->
<system:String x:Key="ExternalNotificationEmailTemplateHello">博士,有新的通知哦!</system:String>
<system:String x:Key="ExternalNotificationEmailTemplateFooterLineOne">您会收到此邮件,是因为您在 MAA 中设置了 SMTP 服务器并开启了邮件通知服务。</system:String>
<system:String x:Key="ExternalNotificationEmailTemplateFooterLineTwo">此邮件为系统自动发送,请勿回复。</system:String>
<system:String x:Key="ExternalNotificationEmailTemplateLinkOfficialSite">官网</system:String>
<system:String x:Key="ExternalNotificationEmailTemplateLinkCopilotSite">作业站</system:String>
<!-- External Notification -->
<!-- External Notification -->
</ResourceDictionary>

View File

@@ -448,6 +448,10 @@
<system:String x:Key="AddTrust">補充低信賴幹員</system:String>
<system:String x:Key="AddUserAdditional">追加自定幹員</system:String>
<system:String x:Key="AddUserAdditionalTip">使用";"作為分隔符,用","分隔操作員姓名和技能,例:史尔特尔,3;艾雅法拉,1</system:String>
<system:String x:Key="UseCopilotList">戰鬥列表</system:String>
<system:String x:Key="UseCopilotListTip">開始前請切換至關卡選擇頁面</system:String>
<system:String x:Key="CopilotAddTask">右鍵添加突襲難度</system:String>
<system:String x:Key="CopilotClearTask">右鍵清除未激活任務</system:String>
<system:String x:Key="LoopTimes">循環次數</system:String>
<system:String x:Key="Start">開始</system:String>
<system:String x:Key="VideoLink">影片連結</system:String>
@@ -461,6 +465,12 @@
請手動編隊後在「開始部署」介面開始(可配合「循環次數」使用)\n\n
5. 現已支援影片辨識,請將攻略影片拖入使用。 \n
需要影片分辨率為 16:9無黑邊、模擬器邊框、異形屏矯正等干擾因素。\n\n
6. 戰鬥列表:\n
選擇作業後,檢查列表下方的關卡名是否正確 (如: CV-EX-1) 。 \n
添加: 左鍵添加正常難度,右鍵添加突襲難度。 \n
清除: 左鍵清空列表,右鍵僅移除未激活的任務。 \n
開始前,需要切換至對應關卡的選擇界面,不支持跨章節導航。 \n
遇到 理智不足、戰鬥失敗、未能以三星結算 時將會中止運行。 \n\n
</system:String>
<system:String x:Key="CopilotFileReadError">讀取檔案失敗!</system:String>
<system:String x:Key="CopilotNoFound">未找到對應作業!</system:String>

View File

@@ -0,0 +1,107 @@
using System.Security.RightsManagement;
using MaaWpfGui.Helper;
using Stylet;
using Vanara.PInvoke;
namespace MaaWpfGui.ViewModels
{
public class CopilotItemViewModel : PropertyChangedBase
{
/// <summary>
/// Initializes a new instance of the <see cref="CopilotItemViewModel"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="filePath">The original Name of file</param>
/// <param name="isChecked">isChecked</param>
public CopilotItemViewModel(string name, string filePath, bool isChecked = true)
{
_name = name;
_filePath = filePath;
_isChecked = isChecked;
}
private string _filePath;
/// <summary>
/// Gets or sets the original_name.
/// </summary>
public string FilePath
{
get => _filePath;
set => SetAndNotify(ref _filePath, value);
}
private string _name;
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name
{
get => _name;
set => SetAndNotify(ref _name, value);
}
private bool _isChecked;
/// <summary>
/// Gets or sets a value indicating whether gets or sets whether the key is checked.
/// </summary>
public bool IsChecked
{
get => _isChecked;
set
{
SetAndNotify(ref _isChecked, value);
Instances.CopilotViewModel.SaveCopilotTask();
}
}
// 换成图标的话要这个,暂时没用
private string _iconPath;
/// <summary>
/// Gets or sets the icon path.
/// </summary>
// ReSharper disable once UnusedMember.Global
public string IconPath
{
get => _iconPath;
set => SetAndNotify(ref _iconPath, value);
}
private string _token;
/// <summary>
/// Gets or sets the token.
/// </summary>
// ReSharper disable once UnusedMember.Global
public string Token
{
get => _token;
set => SetAndNotify(ref _token, value);
}
private string _runStatus;
/// <summary>
/// Gets or sets the running status.
/// </summary>
// 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;
}
}

View File

@@ -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
/// </summary>
public ObservableCollection<LogItemViewModel> LogItemViewModels { get; }
/// <summary>
/// Gets or private sets the view models of Copilot items.
/// </summary>
public ObservableCollection<CopilotItemViewModel> CopilotItemViewModels { get; private set; } = new ObservableCollection<CopilotItemViewModel>();
/// <summary>
/// Initializes a new instance of the <see cref="CopilotViewModel"/> class.
/// </summary>
@@ -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"], (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,159 @@ namespace MaaWpfGui.ViewModels.UI
}
}
/// <summary>
/// Gets or sets a value indicating whether to use auto-formation.
/// </summary>
private bool _useCopilotList = false;
public bool UseCopilotList
{
get => _useCopilotList;
set
{
if (value)
{
_taskType = "Copilot";
}
SetAndNotify(ref _useCopilotList, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether to use auto-formation.
/// </summary>
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 CleanUnableCopilotTask()
{
foreach (var item in CopilotItemViewModels.Where(model => !model.IsChecked).ToList())
{
CopilotItemViewModels.Remove(item);
}
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();
});
}
/// <summary>
/// 更新任务顺序
/// </summary>
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 +742,52 @@ 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(@"(?<=;)(?<name>[^,;]+)(?:, *(?<skill>\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;
}
}
ret &= Instances.AsstProxy.AsstStart();
if (!startAny)
{
// 一个都没启动,怎会有如此无聊之人
Instances.AsstProxy.AsstStop();
_runningState.SetIdle(true);
return;
}
}
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);
}

View File

@@ -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 @@
</Grid.ColumnDefinitions>
<StackPanel
Grid.Row="0"
Margin="0,30,0,0"
Margin="0,10,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Orientation="Vertical">
@@ -43,6 +44,7 @@
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox
Height="30"
@@ -54,6 +56,16 @@
<Button
Grid.Column="1"
Height="30"
hc:BorderElement.CornerRadius="0,0,0,0"
hc:IconElement.Geometry="{StaticResource SearchGeometry}"
BorderThickness="0,1,1,1"
Command="{s:Action SelectFile}"
IsEnabled="{Binding Idle}"
Style="{StaticResource ButtonDefault}"
ToolTip="{DynamicResource SelectTheFileTip}" />
<Button
Grid.Column="2"
Height="30"
hc:BorderElement.CornerRadius="0,4,4,0"
hc:IconElement.Geometry="{StaticResource PasteGeometry}"
BorderThickness="0,1,1,1"
@@ -62,90 +74,217 @@
Style="{StaticResource ButtonDefault}"
ToolTip="{DynamicResource PasteClipboardTip}" />
</Grid>
<Button
Width="120"
Height="50"
Margin="10"
Command="{s:Action SelectFile}"
Content="{DynamicResource SelectTheFile}"
IsEnabled="{Binding Idle}"
ToolTip="{DynamicResource SelectTheFileTip}" />
<Grid
Margin="0,10,0,0"
HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="100" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox
<Grid Height="280" Margin="0,5,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="100" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox
HorizontalAlignment="Center"
Content="{DynamicResource AutoSquad}"
IsChecked="{Binding Form}"
IsEnabled="{Binding Idle}"
IsHitTestVisible="{Binding Idle}"
ToolTip="{DynamicResource AutoSquadTip}" />
<CheckBox
Grid.Column="1"
Margin="10,0,0,0"
HorizontalAlignment="Center"
Content="{DynamicResource AddTrust}"
IsChecked="{Binding AddTrust}"
IsEnabled="{Binding Idle}"
IsHitTestVisible="{Binding Idle}"
Visibility="{c:Binding Form}" />
</Grid>
<Grid
Grid.Row="1"
Margin="0,10,0,-2"
HorizontalAlignment="Center"
Content="{DynamicResource AutoSquad}"
IsChecked="{Binding Form}"
Visibility="{c:Binding Form}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="100" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox
HorizontalAlignment="Center"
VerticalContentAlignment="Center"
Content="{DynamicResource AddUserAdditional}"
IsChecked="{Binding AddUserAdditional}"
IsEnabled="{Binding Idle}"
IsHitTestVisible="{Binding Idle}"
ToolTip="{DynamicResource AddUserAdditionalTip}"
Visibility="{c:Binding Form}" />
<TextBox
Grid.Column="1"
MinWidth="150"
Margin="5,0,0,0"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
IsEnabled="{c:Binding '(Form) and (Idle)'}"
IsHitTestVisible="{Binding AddUserAdditional}"
MaxLines="1"
Text="{Binding UserAdditional, UpdateSourceTrigger=LostFocus}"
ToolTip="{DynamicResource AddUserAdditionalTip}"
Visibility="{c:Binding '(Form) and (AddUserAdditional)'}" />
</Grid>
<CheckBox
Grid.Row="2"
Margin="0,12,0,0"
HorizontalAlignment="Center"
Content="{DynamicResource UseCopilotList}"
IsChecked="{Binding UseCopilotList}"
IsEnabled="{Binding Idle}"
IsHitTestVisible="{Binding Idle}"
ToolTip="{DynamicResource AutoSquadTip}"/>
<CheckBox
Grid.Column="1"
ToolTip="{DynamicResource UseCopilotListTip}" />
<Border
Grid.Row="3"
Width="200"
Margin="0,10,0,0"
BorderBrush="{DynamicResource BorderBrush}"
BorderThickness="1"
CornerRadius="4"
Visibility="{c:Binding UseCopilotList}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<ListBox
x:Name="CopilotList"
dd:DragDrop.IsDragSource="{Binding Idle}"
dd:DragDrop.IsDropTarget="{Binding Idle}"
BorderThickness="0"
DragDrop.Drop="{s:Action CopilotItemIndexChanged}"
IsEnabled="{c:Binding '(Idle) and (StartEnabled)'}"
ItemContainerStyle="{StaticResource CustomListBoxItemStyle}"
ItemsSource="{Binding Path=CopilotItemViewModels}"
ToolTip="{DynamicResource LabelSequenceTip}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!--<maa:TextBlock Text="{Binding ID}" />
<maa:TextBlock Text=". " />-->
<CheckBox
Grid.Column="0"
Content="{c:Binding Name}"
IsChecked="{Binding IsChecked}"
IsHitTestVisible="{Binding ElementName=CopilotList, Path=DataContext.Idle}" />
<Button
Grid.Column="1"
hc:IconElement.Geometry="{StaticResource CloseGeometry}"
Background="Transparent"
BorderThickness="0"
Command="{s:Action DeleteCopilotTask}"
CommandParameter="{c:Binding Index}"
Foreground="{DynamicResource SecondaryTextBrush}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid Grid.Row="1" Margin="5,0,2,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="42" />
<ColumnDefinition Width="42" />
</Grid.ColumnDefinitions>
<TextBox
Margin="0,7,0,5"
VerticalContentAlignment="Center"
IsEnabled="{Binding Idle}"
MaxLines="1"
Text="{Binding CopilotTaskName, UpdateSourceTrigger=LostFocus}" />
<Button
Grid.Column="1"
Margin="2,0,0,0"
hc:IconElement.Geometry="{StaticResource AddGeometry}"
Command="{s:Action AddCopilotTask}"
IsEnabled="{c:Binding '(Idle) and (StartEnabled)'}"
MouseRightButtonUp="{s:Action AddCopilotTask_Adverse}"
ToolTip="{DynamicResource CopilotAddTask}" />
<Button
Grid.Column="2"
Margin="2,0,0,0"
hc:IconElement.Geometry="{StaticResource ErrorGeometry}"
Command="{s:Action ClearCopilotTask}"
IsEnabled="{c:Binding '(Idle) and (StartEnabled)'}"
MouseRightButtonUp="{s:Action CleanUnableCopilotTask}"
ToolTip="{DynamicResource CopilotClearTask}" />
</Grid>
</Grid>
</Border>
<StackPanel
Grid.Row="4"
Margin="0,5,0,0"
HorizontalAlignment="Center"
Content="{DynamicResource AddTrust}"
IsChecked="{Binding AddTrust}"
Visibility="{c:Binding Form}"
IsEnabled="{Binding Idle}"
IsHitTestVisible="{Binding Idle}" Margin="10,0,0,0"/>
Orientation="Horizontal"
Visibility="{c:Binding !UseCopilotList}">
<CheckBox
Margin="0,0,10,0"
VerticalContentAlignment="Center"
Content="{DynamicResource LoopTimes}"
IsChecked="{Binding Loop}" />
<TextBox
Width="60"
Height="30"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
Text="{Binding LoopTimes}" />
</StackPanel>
<controls:TextBlock
Grid.Row="5"
Margin="5,15,5,5"
Block.TextAlignment="Center"
Visibility="{c:Binding !UseCopilotList}">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Url}"
TextDecorations="None">
<TextBlock Text="{Binding UrlText}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock
Grid.Row="6"
Margin="5,5,5,30"
Block.TextAlignment="Center"
Visibility="{c:Binding !UseCopilotList}">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.MapPrts}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource MapPrts}" />
</Hyperlink>
</controls:TextBlock>
</Grid>
<Grid
Margin="0,10,0,25"
Height="30"
HorizontalAlignment="Center">
<Grid Margin="0,10,0,0" HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="100" />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<CheckBox
HorizontalAlignment="Center"
Content="{DynamicResource AddUserAdditional}"
IsChecked="{Binding AddUserAdditional}"
IsEnabled="{Binding Idle}"
IsHitTestVisible="{Binding Idle}"
Visibility="{c:Binding Form}"
ToolTip="{DynamicResource AddUserAdditionalTip}"/>
<TextBox
Grid.Column="1"
IsEnabled="{c:Binding '(Form) and (Idle)'}"
IsHitTestVisible="{Binding AddUserAdditional}"
Text="{Binding UserAdditional, UpdateSourceTrigger=LostFocus}"
VerticalAlignment="Center"
VerticalContentAlignment="Center"
Visibility="{c:Binding '(Form) and (AddUserAdditional)'}"
ToolTip="{DynamicResource AddUserAdditionalTip}"
MinWidth="150"
MaxLines="1"
Margin="5,0,0,0"/>
</Grid>
<StackPanel
Margin="10"
HorizontalAlignment="Center"
IsEnabled="{Binding Idle}"
Orientation="Horizontal">
<CheckBox
Margin="10"
VerticalContentAlignment="Center"
Content="{DynamicResource LoopTimes}"
IsChecked="{Binding Loop}" />
<TextBox
Width="60"
Height="30"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
InputMethod.IsInputMethodEnabled="False"
Text="{Binding LoopTimes}" />
</StackPanel>
<Grid Margin="0,10,0,30">
<Button
Grid.Column="1"
Width="120"
Height="50"
Command="{s:Action Start}"
@@ -153,28 +292,13 @@
IsEnabled="{c:Binding StartEnabled}"
Visibility="{c:Binding Idle}" />
<Button
Grid.Column="1"
Width="120"
Height="50"
Command="{s:Action Stop}"
Content="{DynamicResource Stop}"
Visibility="{c:Binding !Idle}" />
</Grid>
<controls:TextBlock Margin="5" Block.TextAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Url}"
TextDecorations="None">
<TextBlock Text="{Binding UrlText}" />
</Hyperlink>
</controls:TextBlock>
<controls:TextBlock Margin="5" Block.TextAlignment="Center">
<Hyperlink
Cursor="Hand"
NavigateUri="{Binding Source={x:Static constants:MaaUrls.MapPrts}}"
TextDecorations="None">
<TextBlock Text="{DynamicResource MapPrts}" />
</Hyperlink>
</controls:TextBlock>
</StackPanel>
<Grid Grid.Column="1">