From 3d5e05414fa39040e40dd8ab6c41e252fe4fd9b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=99=93=E4=B8=B6=E6=A2=A6=E4=B8=B6=E4=BB=81?= <74444214+Daydreamer114@users.noreply.github.com> Date: Sun, 12 Jan 2025 20:03:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=82=B9=E5=88=BA=E3=80=81=E5=90=8E?= =?UTF-8?q?=E5=8B=A4=E7=A7=8D=E5=AD=90=E5=AD=98=E9=92=B1=20&=20ProcessTask?= =?UTF-8?q?=20=E6=B7=BB=E5=8A=A0=20Input=20=E6=96=B9=E6=B3=95=20(#11521)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 为 ProcessTask 添加文本输入功能 * feat: 点刺、后勤种子存钱 * docs: 为 Input 方法添加文档 * perf: 添加循环刷钱cd检查 * perf: werror * perf: 改变 Input 的 int 值 * perf: 减少 AsstProxy 传参,改用 c:Binding * chore: 界面显示和获取分离 --------- Co-authored-by: uye <99072975+ABA2396@users.noreply.github.com> --- docs/maa_tasks_schema.json | 6 +- docs/zh-cn/protocol/task-schema.md | 7 +- resource/config.json | 1 + resource/tasks.json | 71 +++++++++++++++++- ...oguelike@StartExploreWithSeed-ClickPen.png | Bin 0 -> 1005 bytes ...Roguelike@StartExploreWithSeed-Confirm.png | Bin 0 -> 10857 bytes ...ike@StartExploreWithSeed-SetDifficulty.png | Bin 0 -> 31124 bytes src/MaaCore/Common/AsstTypes.h | 5 +- src/MaaCore/Config/GeneralConfig.cpp | 1 + src/MaaCore/Config/GeneralConfig.h | 1 + .../Roguelike/RoguelikeStageEncounterConfig.h | 23 ++++++ src/MaaCore/Config/TaskData.cpp | 3 + src/MaaCore/Controller/AdbController.cpp | 11 +++ src/MaaCore/Controller/AdbController.h | 3 + src/MaaCore/Controller/ControlScaleProxy.h | 2 + src/MaaCore/Controller/Controller.cpp | 6 ++ src/MaaCore/Controller/Controller.h | 1 + src/MaaCore/Controller/ControllerAPI.h | 2 + .../Controller/PlayToolsController.cpp | 5 ++ src/MaaCore/Controller/PlayToolsController.h | 2 + src/MaaCore/Task/Interface/RoguelikeTask.cpp | 5 ++ src/MaaCore/Task/ProcessTask.cpp | 9 +++ src/MaaCore/Task/ProcessTask.h | 1 + .../Map/RoguelikeRoutingTaskPlugin.cpp | 5 +- .../Task/Roguelike/RoguelikeConfig.cpp | 11 ++- src/MaaCore/Task/Roguelike/RoguelikeConfig.h | 3 + .../RoguelikeCustomStartTaskPlugin.cpp | 37 ++++++++- .../Roguelike/RoguelikeRecruitTaskPlugin.cpp | 3 +- src/MaaWpfGui/Constants/ConfigurationKeys.cs | 2 + src/MaaWpfGui/Main/AsstProxy.cs | 7 +- src/MaaWpfGui/Res/Localizations/en-us.xaml | 1 + src/MaaWpfGui/Res/Localizations/ja-jp.xaml | 1 + src/MaaWpfGui/Res/Localizations/ko-kr.xaml | 1 + src/MaaWpfGui/Res/Localizations/zh-cn.xaml | 1 + src/MaaWpfGui/Res/Localizations/zh-tw.xaml | 1 + .../ViewModels/UI/TaskQueueViewModel.cs | 3 +- .../RoguelikeSettingsUserControlModel.cs | 17 +++++ .../RoguelikeSettingsUserControl.xaml | 9 +++ 38 files changed, 252 insertions(+), 15 deletions(-) create mode 100644 resource/template/Sarkaz@Roguelike@StartExploreWithSeed-ClickPen.png create mode 100644 resource/template/Sarkaz@Roguelike@StartExploreWithSeed-Confirm.png create mode 100644 resource/template/Sarkaz@Roguelike@StartExploreWithSeed-SetDifficulty.png diff --git a/docs/maa_tasks_schema.json b/docs/maa_tasks_schema.json index a514ce44b4..fc8deba3a1 100644 --- a/docs/maa_tasks_schema.json +++ b/docs/maa_tasks_schema.json @@ -47,10 +47,14 @@ }, "action": { "type": "string", - "pattern": "ClickSelf|ClickRand|DoNothing|Stop|ClickRect|Swipe", + "pattern": "ClickSelf|ClickRand|DoNothing|Stop|ClickRect|Swipe|Input", "default": "DoNothing", "description": "可选项,表示识别到后的动作\n不填写时默认为 DoNothing" }, + "inputText": { + "type": "string", + "description": "可选项,当 action 为 Input 时有效,表示要输入的文本" + }, "sub": { "$ref": "#/definitions/TaskNameList", "description": "可选项,子任务。会在执行完当前任务后,依次执行每一个子任务\n可以套娃,子任务再套子任务。但要注意不要写出了死循环" diff --git a/docs/zh-cn/protocol/task-schema.md b/docs/zh-cn/protocol/task-schema.md index 82c98fcf83..735b0cb3c3 100644 --- a/docs/zh-cn/protocol/task-schema.md +++ b/docs/zh-cn/protocol/task-schema.md @@ -32,6 +32,7 @@ icon: material-symbols:task // - DoNothing: 什么都不做 // - Stop: 停止当前任务 // - Swipe: 滑动,对应 specificRect 与 rectMove 字段 + // - Input: 输入文本,要求 algorithm 为 JustReturn,对应 inputText 字段 "sub": ["SubTaskName1", "SubTaskName2"], // 可选项,子任务,不推荐使用。会在执行完当前任务后,依次执行每一个子任务 @@ -138,9 +139,13 @@ icon: material-symbols:task "isAscii": false, // 可选项,要识别的文字内容是否为 ASCII 码字符 // 不填写默认 false - "withoutDet": false // 可选项,是否不使用检测模型 + "withoutDet": false, // 可选项,是否不使用检测模型 // 不填写默认 false + /* 以下字段仅当 algorithm 为 JustReturn,action 为 Input 时有效 */ + + "inputText": "A string text." // 必选项,要输入的文字内容,以字符串的形式 + } } ``` diff --git a/resource/config.json b/resource/config.json index a7a5059704..0498a6e158 100644 --- a/resource/config.json +++ b/resource/config.json @@ -84,6 +84,7 @@ "screencapEncode": "[Adb] -s [AdbSerial] exec-out screencap -p", "click": "[Adb] -s [AdbSerial] shell input tap [x] [y]", "swipe": "[Adb] -s [AdbSerial] shell input swipe [x1] [y1] [x2] [y2] [duration]", + "input": "[Adb] -s [AdbSerial] shell input text [text]", "start": "[Adb] -s [AdbSerial] shell am start -n [PackageName]/com.u8.sdk.U8UnityContext", "stop": "[Adb] -s [AdbSerial] shell am force-stop [PackageName]", "back_to_home": "[Adb] -s [AdbSerial] shell input keyevent HOME", diff --git a/resource/tasks.json b/resource/tasks.json index 0da93e1e5a..464e316f32 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -6653,6 +6653,7 @@ "Roguelike@Begin": { "algorithm": "JustReturn", "next": [ + "Roguelike@StartExploreWithSeed", "Roguelike@ChooseDifficulty", "Roguelike@StartExplore", "Roguelike@Stages#next", @@ -6777,7 +6778,13 @@ "Roguelike@ClickToStartPointAfterFailed": { "doc": "因为是从肉鸽失败界面进入,删除了对下个stage的判断", "baseTask": "Roguelike@ClickToStartPoint", - "next": ["Roguelike@StartExplore", "Roguelike@StartUpThemes#next", "Roguelike@ClickToStartPointAfterFailed"] + "next": [ + "Roguelike@StartExploreWithSeed", + "Roguelike@StartExplore", + "Roguelike@StartExploreCD", + "Roguelike@StartUpThemes#next", + "Roguelike@ClickToStartPointAfterFailed" + ] }, "Roguelike@CloseCollection": { "Doc": "base_task", @@ -7737,6 +7744,62 @@ "postDelay": 1000, "next": ["Roguelike@StartExplore", "Roguelike@StartExploreCD"] }, + "Roguelike@StartExploreWithSeed": { + "Doc": "萨卡兹点刺刷钱,由 cpp 内启用", + "maxTimes": 0, + "exceededNext": ["Roguelike@StartExplore"], + "algorithm": "OcrDetect", + "action": "ClickSelf", + "text": ["启用参数"], + "roi": [851, 567, 93, 33], + "next": ["Roguelike@StartExploreWithSeed-ClickPen"] + }, + "Roguelike@StartExploreWithSeed-ClickPen": { + "template": "empty.png", + "action": "ClickSelf", + "roi": [640, 163, 145, 141], + "next": ["Roguelike@StartExploreWithSeed-ClickInputBox"] + }, + "Roguelike@StartExploreWithSeed-ClickInputBox": { + "algorithm": "OcrDetect", + "action": "ClickSelf", + "text": ["参数"], + "roi": [323, 267, 200, 147], + "next": ["Roguelike@StartExploreWithSeed-InputSeed"] + }, + "Roguelike@StartExploreWithSeed-InputSeed": { + "algorithm": "JustReturn", + "action": "Input", + "inputText": "", + "next": ["Roguelike@StartExploreWithSeed-Confirm"] + }, + "Roguelike@StartExploreWithSeed-Confirm": { + "Doc": "找到一个 “RecruitConfirm.png” 可能复用,但是分数太低,放弃", + "template": "empty.png", + "action": "ClickSelf", + "roi": [645, 393, 585, 173], + "postDelay": 1000, + "next": [ + "Roguelike@StartExploreWithSeed-Confirm", + "Roguelike@StartExploreWithSeed-SetDifficulty", + "Roguelike@StartExploreWithSeed-BackToMainPage" + ] + }, + "Roguelike@StartExploreWithSeed-SetDifficulty": { + "template": "empty.png", + "action": "ClickSelf", + "roi": [847, 246, 276, 205], + "next": ["Roguelike@StartExploreWithSeed-BackToMainPage"] + }, + "Roguelike@StartExploreWithSeed-BackToMainPage": { + "Doc": "识别到 ‘停用参数’ 就行了,不做难度解锁的检查了", + "algorithm": "OcrDetect", + "text": ["停用参数"], + "action": "ClickRect", + "roi": [631, 209, 118, 49], + "specificRect": [600, 5, 300, 70], + "next": ["Roguelike@StartExplore", "Roguelike@StartExploreWithSeed-BackToMainPage"] + }, "Roguelike@StrategyChange": { "baseTask": "Roguelike@StrategyChange_default" }, @@ -10944,6 +11007,12 @@ "Sarkaz@Roguelike@StartExplore": { "roi": [1014, 481, 266, 219] }, + "Sarkaz@Roguelike@StartExploreWithSeed-ClickPen": {}, + "Sarkaz@Roguelike@StartExploreWithSeed-Confirm": {}, + "Sarkaz@Roguelike@StartExploreWithSeed-SetDifficulty": {}, + "Sarkaz@Roguelike@StartExploreWithSeed-InputSeed": { + "inputText": "U1eIA1I29844Ae925i,rogue_4,6" + }, "Sarkaz@Roguelike@StrategyChange-FastInvestment": { "baseTask": "Sarkaz@Roguelike@StrategyChange_mode1", "text": ["_fastInvestment", "_exit"], diff --git a/resource/template/Sarkaz@Roguelike@StartExploreWithSeed-ClickPen.png b/resource/template/Sarkaz@Roguelike@StartExploreWithSeed-ClickPen.png new file mode 100644 index 0000000000000000000000000000000000000000..35cafb29ccb936cbb38a311dd3dcdd9b31aff060 GIT binary patch literal 1005 zcmVSWoSd7R zo0^)Mn3$NCmzS27mX(#2l$4Z_k&%#)kd2Lvi;Ihjii(MeiHL}ZhK7cOgoJ~GgMxyB zfq{X4e}8>_eSCa;dwY9&dU|7i89_U~1G7uJL7x7o$Kkb~o_C24op<9^7Y@fhEF{Edl z4^jhi_1mHY*h60j;_&dH9ROerev}5#r%{AawyE^B*JbhYjSJ{mr#@W6HG21FIp!i- z*Mpf3|7#MYr`@aU`IgVBb8_yW{lZME^s)nZme`9|Ek2Sc9Dj$o$FWaS1< z%j^?`JGs_*Rc+w3diLCi9rJl~*r+u_@H9NqwH9YQr)d9W)JpzE7ZZdxT7X)QRy)Dm zq5)g)COJjzsjKC}nhSKbH^xB~t6?GHF>LlGIa$SOxwz&e44YTcWfQIF!5=G56Bn6{oRBG-WSKguQtNn{h#xdd*l?_x200000NkvXXu0mjfFKo4; literal 0 HcmV?d00001 diff --git a/resource/template/Sarkaz@Roguelike@StartExploreWithSeed-Confirm.png b/resource/template/Sarkaz@Roguelike@StartExploreWithSeed-Confirm.png new file mode 100644 index 0000000000000000000000000000000000000000..6d203489cc9fe21fe40407048c6440dfc4913566 GIT binary patch literal 10857 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.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 literal 0 HcmV?d00001 diff --git a/src/MaaCore/Common/AsstTypes.h b/src/MaaCore/Common/AsstTypes.h index 672d780507..82b83ae049 100644 --- a/src/MaaCore/Common/AsstTypes.h +++ b/src/MaaCore/Common/AsstTypes.h @@ -336,6 +336,7 @@ enum class ProcessTaskAction DoNothing = 0x200, // 什么都不做 Stop = 0x400, // 停止当前Task Swipe = 0x1000, // 滑动 + Input = 0x2000, // 输入文本 }; inline ProcessTaskAction get_action_type(std::string action_str) @@ -345,6 +346,7 @@ inline ProcessTaskAction get_action_type(std::string action_str) { "", ProcessTaskAction::DoNothing }, { "donothing", ProcessTaskAction::DoNothing }, { "clickself", ProcessTaskAction::ClickSelf }, { "clickrect", ProcessTaskAction::ClickRect }, { "stop", ProcessTaskAction::Stop }, { "swipe", ProcessTaskAction::Swipe }, + { "input", ProcessTaskAction::Input }, }; if (auto it = action_map.find(action_str); it != action_map.end()) { return it->second; @@ -358,7 +360,7 @@ inline std::string enum_to_string(ProcessTaskAction action) { ProcessTaskAction::Invalid, "Invalid" }, { ProcessTaskAction::DoNothing, "DoNothing" }, { ProcessTaskAction::BasicClick, "BasicClick" }, { ProcessTaskAction::ClickSelf, "ClickSelf" }, { ProcessTaskAction::ClickRect, "ClickRect" }, { ProcessTaskAction::Stop, "Stop" }, - { ProcessTaskAction::Swipe, "Swipe" }, + { ProcessTaskAction::Swipe, "Swipe" }, { ProcessTaskAction::Input, "Input" }, }; if (auto it = action_map.find(action); it != action_map.end()) { return it->second; @@ -490,6 +492,7 @@ struct TaskInfo : public TaskPipelineInfo // 即识别到了res,点击res + result_move的位置 bool cache = false; // 是否使用缓存区域 std::vector special_params; // 某些任务会用到的特殊参数 + std::string input_text; // 输入任务的文字,目前希望仅针对 Input 任务有效, algorithm 为 JustReturn }; using TaskPtr = std::shared_ptr; diff --git a/src/MaaCore/Config/GeneralConfig.cpp b/src/MaaCore/Config/GeneralConfig.cpp index 93d5bb376b..9508fb7bd6 100644 --- a/src/MaaCore/Config/GeneralConfig.cpp +++ b/src/MaaCore/Config/GeneralConfig.cpp @@ -83,6 +83,7 @@ bool asst::GeneralConfig::parse(const json::value& json) adb.display_id = cfg_json.get("displayId", base_cfg.display_id); adb.uuid = cfg_json.get("uuid", base_cfg.uuid); adb.click = cfg_json.get("click", base_cfg.click); + adb.input = cfg_json.get("input", base_cfg.input); adb.swipe = cfg_json.get("swipe", base_cfg.swipe); adb.press_esc = cfg_json.get("pressEsc", base_cfg.press_esc); adb.display = cfg_json.get("display", base_cfg.display); diff --git a/src/MaaCore/Config/GeneralConfig.h b/src/MaaCore/Config/GeneralConfig.h index 1b239590d7..a0fd0e3af9 100644 --- a/src/MaaCore/Config/GeneralConfig.h +++ b/src/MaaCore/Config/GeneralConfig.h @@ -70,6 +70,7 @@ struct AdbCfg std::string display_id; std::string uuid; std::string click; + std::string input; std::string swipe; std::string press_esc; std::string display; diff --git a/src/MaaCore/Config/Roguelike/RoguelikeStageEncounterConfig.h b/src/MaaCore/Config/Roguelike/RoguelikeStageEncounterConfig.h index 1659d3c8cd..ea55c42249 100644 --- a/src/MaaCore/Config/Roguelike/RoguelikeStageEncounterConfig.h +++ b/src/MaaCore/Config/Roguelike/RoguelikeStageEncounterConfig.h @@ -46,6 +46,29 @@ public: const auto& get_event_names(const std::string& theme) const noexcept { return m_event_names.at(theme); } + bool set_event(std::string theme, RoguelikeMode mode, std::string event_name, int choose, int option_num) + { + std::pair key = std::make_pair(theme, static_cast(mode)); + if (theme == "Sarkaz" || theme == "Sami") { + // 在调试器里发现 m_events 中,Sami 和 Sarkaz 的 mode 只有 -1 + key.second = -1; + } + // 边界检查 + auto outerIt = m_events.find(key); + if (outerIt == m_events.end()) { + return false; + } + auto& innerMap = outerIt->second; + auto innerIt = innerMap.find(event_name); + if (innerIt == innerMap.end()) { + return false; + } + // 修改事件选择 + m_events[key][event_name].default_choose = choose; + m_events[key][event_name].option_num = option_num; + return true; + } + enum class ComparisonType { GreaterThan, diff --git a/src/MaaCore/Config/TaskData.cpp b/src/MaaCore/Config/TaskData.cpp index 26cbcb9304..78992f0303 100644 --- a/src/MaaCore/Config/TaskData.cpp +++ b/src/MaaCore/Config/TaskData.cpp @@ -431,6 +431,7 @@ asst::TaskPtr asst::TaskData::generate_task_info(std::string_view name) ASST_TASKDATA_GET_VALUE_OR("rectMove", rect_move); ASST_TASKDATA_GET_VALUE_OR("specificRect", specific_rect); ASST_TASKDATA_GET_VALUE_OR("specialParams", special_params); + ASST_TASKDATA_GET_VALUE_OR("inputText", input_text); // 展开五个任务列表中的虚任务 ASST_TASKDATA_GET_VALUE_OR_LAZY("next", next, false); @@ -933,6 +934,7 @@ bool asst::TaskData::syntax_check(std::string_view task_name, const json::value& "specialParams", "sub", "subErrorIgnored", // specific + "inputText" } }, }; // clang-format on @@ -940,6 +942,7 @@ bool asst::TaskData::syntax_check(std::string_view task_name, const json::value& static const std::unordered_map> allowed_key_under_action = { { ProcessTaskAction::ClickRect, { "specificRect" } }, { ProcessTaskAction::Swipe, { "specificRect", "rectMove" } }, + { ProcessTaskAction::Input, { "inputText" } }, }; auto is_doc = [&](std::string_view key) { diff --git a/src/MaaCore/Controller/AdbController.cpp b/src/MaaCore/Controller/AdbController.cpp index 554fee0d5e..628ce07554 100644 --- a/src/MaaCore/Controller/AdbController.cpp +++ b/src/MaaCore/Controller/AdbController.cpp @@ -336,6 +336,16 @@ bool asst::AdbController::click(const Point& p) return call_command(cur_cmd).has_value(); } +bool asst::AdbController::input(const std::string& text) +{ + if (text == "") { + Log.error("empty text"); + } + + std::string cur_cmd = utils::string_replace_all(m_adb.input, { { "[text]", text } }); + return call_command(cur_cmd).has_value(); +} + bool asst::AdbController::swipe( const Point& p1, const Point& p2, @@ -996,6 +1006,7 @@ bool asst::AdbController::connect(const std::string& adb_path, const std::string } m_adb.click = cmd_replace(adb_cfg.click); + m_adb.input = cmd_replace(adb_cfg.input); m_adb.swipe = cmd_replace(adb_cfg.swipe); m_adb.press_esc = cmd_replace(adb_cfg.press_esc); m_adb.screencap_raw_with_gzip = cmd_replace(adb_cfg.screencap_raw_with_gzip); diff --git a/src/MaaCore/Controller/AdbController.h b/src/MaaCore/Controller/AdbController.h index a0081bf147..7808b465e5 100644 --- a/src/MaaCore/Controller/AdbController.h +++ b/src/MaaCore/Controller/AdbController.h @@ -44,6 +44,8 @@ public: virtual bool click(const Point& p) override; + virtual bool input(const std::string& text) override; + virtual bool swipe( const Point& p1, const Point& p2, @@ -117,6 +119,7 @@ protected: std::string call_minitouch; std::string call_maatouch; std::string click; + std::string input; std::string swipe; std::string press_esc; diff --git a/src/MaaCore/Controller/ControlScaleProxy.h b/src/MaaCore/Controller/ControlScaleProxy.h index 32923849ee..5cf2c90d5d 100644 --- a/src/MaaCore/Controller/ControlScaleProxy.h +++ b/src/MaaCore/Controller/ControlScaleProxy.h @@ -27,6 +27,8 @@ public: bool click(const Point& p); bool click(const Rect& rect); + bool input(const std::string text); + bool swipe( const Point& p1, const Point& p2, diff --git a/src/MaaCore/Controller/Controller.cpp b/src/MaaCore/Controller/Controller.cpp index 9274898c8d..6f15aa7061 100644 --- a/src/MaaCore/Controller/Controller.cpp +++ b/src/MaaCore/Controller/Controller.cpp @@ -173,6 +173,12 @@ bool asst::Controller::click(const Rect& rect) return m_scale_proxy->click(rect); } +bool asst::Controller::input(const std::string& text) +{ + CHECK_EXIST(m_controller, false); + return m_controller->input(text); +} + bool asst::Controller::swipe( const Point& p1, const Point& p2, diff --git a/src/MaaCore/Controller/Controller.h b/src/MaaCore/Controller/Controller.h index 4ce09a2ee8..a32c20ddaa 100644 --- a/src/MaaCore/Controller/Controller.h +++ b/src/MaaCore/Controller/Controller.h @@ -68,6 +68,7 @@ public: bool click(const Point& p); bool click(const Rect& rect); + bool input(const std::string& text); bool swipe( const Point& p1, diff --git a/src/MaaCore/Controller/ControllerAPI.h b/src/MaaCore/Controller/ControllerAPI.h index 93dadcdd5a..b543e2e38c 100644 --- a/src/MaaCore/Controller/ControllerAPI.h +++ b/src/MaaCore/Controller/ControllerAPI.h @@ -42,6 +42,8 @@ public: virtual bool click(const Point& p) = 0; + virtual bool input(const std::string& text) = 0; + virtual bool swipe( const Point& p1, const Point& p2, diff --git a/src/MaaCore/Controller/PlayToolsController.cpp b/src/MaaCore/Controller/PlayToolsController.cpp index e8db7ae617..2735a7dcb3 100644 --- a/src/MaaCore/Controller/PlayToolsController.cpp +++ b/src/MaaCore/Controller/PlayToolsController.cpp @@ -120,6 +120,11 @@ bool asst::PlayToolsController::click(const Point& p) return toucher_down(p) && toucher_up(p); } +bool asst::PlayToolsController::input([[maybe_unused]] const std::string& text) +{ + return true; +} + bool asst::PlayToolsController::swipe( const Point& p1, const Point& p2, diff --git a/src/MaaCore/Controller/PlayToolsController.h b/src/MaaCore/Controller/PlayToolsController.h index 6dfb3ca344..ccb55dabd4 100644 --- a/src/MaaCore/Controller/PlayToolsController.h +++ b/src/MaaCore/Controller/PlayToolsController.h @@ -37,6 +37,8 @@ public: virtual bool click(const Point& p) override; + virtual bool input(const std::string& text) override; + virtual bool swipe( const Point& p1, const Point& p2, diff --git a/src/MaaCore/Task/Interface/RoguelikeTask.cpp b/src/MaaCore/Task/Interface/RoguelikeTask.cpp index 9bb8e273a2..30b5ecdb14 100644 --- a/src/MaaCore/Task/Interface/RoguelikeTask.cpp +++ b/src/MaaCore/Task/Interface/RoguelikeTask.cpp @@ -123,6 +123,11 @@ bool asst::RoguelikeTask::set_params(const json::value& params) m_roguelike_task_ptr->set_times_limit("StageTraderInvestCancel", 0); m_roguelike_task_ptr->set_times_limit("StageTraderLeaveConfirm", INT_MAX); } + // 萨卡兹种子刷钱 + if (theme == RoguelikeTheme::Sarkaz && params.get("start_with_seed", false)) { + m_roguelike_task_ptr->set_times_limit("Roguelike@StartExploreWithSeed", INT_MAX); + RoguelikeStageEncounter.set_event(theme, mode, "相遇", 3, 4); + } } else { // 重置战斗后奖励next diff --git a/src/MaaCore/Task/ProcessTask.cpp b/src/MaaCore/Task/ProcessTask.cpp index 94c0a6e27c..fbf9fa17e1 100644 --- a/src/MaaCore/Task/ProcessTask.cpp +++ b/src/MaaCore/Task/ProcessTask.cpp @@ -195,6 +195,10 @@ ProcessTask::NodeStatus ProcessTask::run_action(const HitDetail& hits) const exec_click_task(rect); return NodeStatus::Success; } + case ProcessTaskAction::Input: { + exec_input_task(task->input_text); + return NodeStatus::Success; + } case ProcessTaskAction::Swipe: { size_t param_size = task->special_params.size(); // Warning: 这里的后两个参数 slope_in 和 slope_out 是 double 类型,但是在 json 中是 int 类型 @@ -404,6 +408,11 @@ void ProcessTask::exec_click_task(const Rect& matched_rect) const ctrler()->click(matched_rect); } +void ProcessTask::exec_input_task(const std::string& text) const +{ + ctrler()->input(text); +} + void ProcessTask::exec_swipe_task( const Rect& r1, const Rect& r2, diff --git a/src/MaaCore/Task/ProcessTask.h b/src/MaaCore/Task/ProcessTask.h index c37e2cb1b0..351cf1fe7c 100644 --- a/src/MaaCore/Task/ProcessTask.h +++ b/src/MaaCore/Task/ProcessTask.h @@ -68,6 +68,7 @@ protected: int calc_post_delay(TaskConstPtr task) const; void exec_click_task(const Rect& matched_rect) const; + void exec_input_task(const std::string& text) const; void exec_swipe_task( const Rect& r1, const Rect& r2, diff --git a/src/MaaCore/Task/Roguelike/Map/RoguelikeRoutingTaskPlugin.cpp b/src/MaaCore/Task/Roguelike/Map/RoguelikeRoutingTaskPlugin.cpp index ddbf2082fc..509b36249c 100644 --- a/src/MaaCore/Task/Roguelike/Map/RoguelikeRoutingTaskPlugin.cpp +++ b/src/MaaCore/Task/Roguelike/Map/RoguelikeRoutingTaskPlugin.cpp @@ -12,7 +12,7 @@ #include "Vision/Miscellaneous/BrightPointAnalyzer.h" #include "Vision/MultiMatcher.h" -bool asst::RoguelikeRoutingTaskPlugin::load_params([[maybe_unused]] const json::value& params) +bool asst::RoguelikeRoutingTaskPlugin::load_params(const json::value& params) { LogTraceFunction; const std::string& theme = m_config->get_theme(); @@ -37,7 +37,8 @@ bool asst::RoguelikeRoutingTaskPlugin::load_params([[maybe_unused]] const json:: const RoguelikeMode& mode = m_config->get_mode(); const std::string squad = params.get("squad", ""); - if (mode == RoguelikeMode::Investment && squad == "点刺成锭分队") { + if (mode == RoguelikeMode::Investment && + (squad == "点刺成锭分队" || (squad == "后勤分队" && params.get("start_with_seed", false)))) { m_routing_strategy = RoutingStrategy::FastInvestment; return true; } diff --git a/src/MaaCore/Task/Roguelike/RoguelikeConfig.cpp b/src/MaaCore/Task/Roguelike/RoguelikeConfig.cpp index 84c2372641..62dbffeb21 100644 --- a/src/MaaCore/Task/Roguelike/RoguelikeConfig.cpp +++ b/src/MaaCore/Task/Roguelike/RoguelikeConfig.cpp @@ -28,6 +28,7 @@ bool asst::RoguelikeConfig::verify_and_load_params(const json::value& params) return false; } + m_start_with_seed = params.get("start_with_seed", false); m_start_with_elite_two = params.get("start_with_elite_two", false); m_only_start_with_elite_two = params.get("only_start_with_elite_two", false); if (mode != RoguelikeMode::Collectible && (m_start_with_elite_two || m_only_start_with_elite_two)) { @@ -52,9 +53,13 @@ bool asst::RoguelikeConfig::verify_and_load_params(const json::value& params) // 点刺成锭分队特殊策略 if (m_theme == "Sarkaz") { - if (m_mode == RoguelikeMode::Investment && params.get("squad", "") == "点刺成锭分队") { - // 启用特殊策略,联动 RoguelikeRoutingTaskPlugin - Task.set_task_base(strategy_task, "Sarkaz@Roguelike@StrategyChange-FastInvestment"); + auto squad = params.get("squad", ""); + if (m_mode == RoguelikeMode::Investment && + (squad == "点刺成锭分队" || (squad == "后勤分队" && m_start_with_seed))) { + if (squad == "点刺成锭分队") { + // 启用特殊策略,联动 RoguelikeRoutingTaskPlugin + Task.set_task_base(strategy_task, "Sarkaz@Roguelike@StrategyChange-FastInvestment"); + } // 禁用前 2 层的 <思维负荷干员编队> 功能 Task.set_task_base( "Sarkaz@Roguelike@StageBurdenOperation", diff --git a/src/MaaCore/Task/Roguelike/RoguelikeConfig.h b/src/MaaCore/Task/Roguelike/RoguelikeConfig.h index 4a79a1477a..a0db1c0b18 100644 --- a/src/MaaCore/Task/Roguelike/RoguelikeConfig.h +++ b/src/MaaCore/Task/Roguelike/RoguelikeConfig.h @@ -155,6 +155,8 @@ public: int get_floor() const { return m_floor; } + bool get_start_with_seed() const { return m_start_with_seed; } + private: // ------------------ 招募 ------------------ bool m_team_full_without_rookie = false; // 编队内没有预干员 @@ -173,6 +175,7 @@ private: int m_hp = 0; // 当前生命值 int m_floor = 0; // 当前到达层数 int m_formation_upper_limit = 6; // 当前编队上限 + bool m_start_with_seed = false; // 种子刷钱 public: // ------------------ 密文板 ------------------ diff --git a/src/MaaCore/Task/Roguelike/RoguelikeCustomStartTaskPlugin.cpp b/src/MaaCore/Task/Roguelike/RoguelikeCustomStartTaskPlugin.cpp index 6e66992173..8a1a026345 100644 --- a/src/MaaCore/Task/Roguelike/RoguelikeCustomStartTaskPlugin.cpp +++ b/src/MaaCore/Task/Roguelike/RoguelikeCustomStartTaskPlugin.cpp @@ -47,8 +47,16 @@ bool asst::RoguelikeCustomStartTaskPlugin::verify(AsstMsg msg, const json::value bool asst::RoguelikeCustomStartTaskPlugin::load_params(const json::value& params) { - set_custom(RoguelikeCustomType::Squad, params.get("squad", "")); // 开局分队 - set_custom(RoguelikeCustomType::Roles, params.get("roles", "")); // 开局职业组 + LogTraceFunction; + + set_custom(RoguelikeCustomType::Squad, params.get("squad", "")); // 开局分队 + if (params.get("start_with_seed", false)) { // 种子刷钱,强制随心所欲 + set_custom(RoguelikeCustomType::Roles, "随心所欲"); + } + else { + set_custom(RoguelikeCustomType::Roles, params.get("roles", "")); // 开局职业组 + } + set_custom(RoguelikeCustomType::CoreChar, params.get("core_char", "")); // 开局干员名 set_custom(RoguelikeCustomType::UseSupport, params.get("use_support", false) ? "1" : "0"); // 开局干员是否为助战干员 set_custom( @@ -88,6 +96,8 @@ bool asst::RoguelikeCustomStartTaskPlugin::_run() bool asst::RoguelikeCustomStartTaskPlugin::hijack_squad() { + LogTraceFunction; + constexpr size_t SwipeTimes = 7; for (size_t i = 0; i != SwipeTimes; ++i) { auto image = ctrler()->get_image(); @@ -112,6 +122,8 @@ bool asst::RoguelikeCustomStartTaskPlugin::hijack_squad() bool asst::RoguelikeCustomStartTaskPlugin::hijack_roles() { + LogTraceFunction; + auto image = ctrler()->get_image(); OCRer analyzer(image); analyzer.set_task_info("RoguelikeCustom-HijackRoles"); @@ -127,6 +139,27 @@ bool asst::RoguelikeCustomStartTaskPlugin::hijack_roles() bool asst::RoguelikeCustomStartTaskPlugin::hijack_core_char() { + LogTraceFunction; + + if (m_config->get_start_with_seed()) { + Log.trace("Start with seed"); + auto image = ctrler()->get_image(); + OCRer analyzer(image); + analyzer.set_task_info("RoguelikeCustom-HijackCoChar"); + analyzer.set_roi({ 186, 500, 913, 200 }); + analyzer.set_required({ "招募" }); + if (!analyzer.analyze()) { + return false; + } + const auto& role_rect = analyzer.get_result().front().rect; + ctrler()->click(role_rect); + + m_config->set_use_support(m_customs[RoguelikeCustomType::UseSupport] == "1"); + m_config->set_use_nonfriend_support(m_customs[RoguelikeCustomType::UseNonfriendSupport] == "1"); + m_config->set_core_char(m_customs[RoguelikeCustomType::CoreChar]); + return true; + } + const std::string& char_name = m_customs[RoguelikeCustomType::CoreChar]; static const std::unordered_map RoleOcrNameMap = { diff --git a/src/MaaCore/Task/Roguelike/RoguelikeRecruitTaskPlugin.cpp b/src/MaaCore/Task/Roguelike/RoguelikeRecruitTaskPlugin.cpp index ccf331a895..57d8ee4924 100644 --- a/src/MaaCore/Task/Roguelike/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MaaCore/Task/Roguelike/RoguelikeRecruitTaskPlugin.cpp @@ -73,7 +73,8 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() ++m_recruit_count; if (m_config->get_theme() == "Sarkaz" && m_config->get_mode() == RoguelikeMode::Investment && - m_config->get_squad() == "点刺成锭分队") { + (m_config->get_squad() == "点刺成锭分队" || + (m_config->get_squad() == "后勤分队" && m_config->get_start_with_seed()))) { ProcessTask(*this, { "Sarkaz@RoguelikeRecruit-GiveUp" }).run(); return true; } diff --git a/src/MaaWpfGui/Constants/ConfigurationKeys.cs b/src/MaaWpfGui/Constants/ConfigurationKeys.cs index 7d628e956b..7bfdd4f975 100755 --- a/src/MaaWpfGui/Constants/ConfigurationKeys.cs +++ b/src/MaaWpfGui/Constants/ConfigurationKeys.cs @@ -142,6 +142,8 @@ namespace MaaWpfGui.Constants public const string RoguelikeDeploymentWithPause = "Roguelike.DeploymentWithPause"; public const string RoguelikeStopAtFinalBoss = "Roguelike.ExitAtFinalBoss"; public const string RoguelikeStopAtMaxLevel = "Roguelike.StopAtMaxLevel"; + public const string RoguelikeStartWithSeed = "Roguelike.StartWithSeed"; + public const string ReclamationTheme = "Reclamation.Theme"; public const string ReclamationMode = "Reclamation.Mode"; public const string ReclamationToolToCraft = "Reclamation.ToolToCraft"; diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs index 88feea6344..9f4818dacd 100644 --- a/src/MaaWpfGui/Main/AsstProxy.cs +++ b/src/MaaWpfGui/Main/AsstProxy.cs @@ -2434,6 +2434,7 @@ namespace MaaWpfGui.Main /// 是否用骰子刷新商店购买特殊商品,目前支持水月肉鸽的指路鳞 /// 是否在五层BOSS前停下来 /// 是否在满级时停止任务 + /// 是否使用刷钱种子 /// 是否成功。 public bool AsstAppendRoguelike( int mode, @@ -2458,7 +2459,8 @@ namespace MaaWpfGui.Main string theme, bool refreshTraderWithDice, bool stopAtFinalBoss, - bool stopAtMaxLevel) + bool stopAtMaxLevel, + bool startWithSeed) { var taskParams = new JObject { @@ -2518,9 +2520,10 @@ namespace MaaWpfGui.Main taskParams["refresh_trader_with_dice"] = theme == "Mizuki" && refreshTraderWithDice; taskParams["stop_at_final_boss"] = mode == 0 && stopAtFinalBoss; - taskParams["stop_at_max_level"] = mode == 0 && stopAtMaxLevel; + taskParams["start_with_seed"] = startWithSeed; + AsstTaskId id = AsstAppendTaskWithEncoding("Roguelike", taskParams); _latestTaskId[TaskType.Roguelike] = id; return id != 0; diff --git a/src/MaaWpfGui/Res/Localizations/en-us.xaml b/src/MaaWpfGui/Res/Localizations/en-us.xaml index 0d1733db2a..e919ff6f9f 100644 --- a/src/MaaWpfGui/Res/Localizations/en-us.xaml +++ b/src/MaaWpfGui/Res/Localizations/en-us.xaml @@ -144,6 +144,7 @@ Don't abort Auto IS until the end of battle Stop before final boss Stop when max level is achieved + 启用刷钱种子 Pause Deployment (Pause Trick) (Experimental) Use ADB Lite (Experimental) Kill ADB On Exit diff --git a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml index c5cc84048f..e9ed0d8740 100644 --- a/src/MaaWpfGui/Res/Localizations/ja-jp.xaml +++ b/src/MaaWpfGui/Res/Localizations/ja-jp.xaml @@ -144,6 +144,7 @@ 自動ローグ 戦闘終了まえに「停止」を遅らせる 第5階層のボスの手前で一時停止する 最大レベル達成時に停止 + 启用刷钱种子 統合戦略/保全駐在でポーズトリックを使用します(ベータ機能のため非推奨です) 軽量ADBを使用(実験機能) 終了時にADBを終了する diff --git a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml index 27ea1634a9..61bd168e89 100644 --- a/src/MaaWpfGui/Res/Localizations/ko-kr.xaml +++ b/src/MaaWpfGui/Res/Localizations/ko-kr.xaml @@ -144,6 +144,7 @@ 통합전략 중지 시 전투 클리어 후 작업 종료 5스테이지 보스 앞에서 일시정지 최대 레벨 달성 시 중지 + 启用刷钱种子 일시정지 상태로 배치하기 - 통합전략, 자동 작전, 보안 파견에 적용 (비권장) ADB Lite 사용 (실험적) 종료 시 ADB도 종료 diff --git a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml index efdbc8c9ad..b4efc5e34f 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-cn.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-cn.xaml @@ -144,6 +144,7 @@ 自动肉鸽在战斗结束前延迟「停止」动作 在第五层 BOSS 前暂停 满级后自动停止 + 启用刷钱种子(美愿) 划火柴模式(自动战斗) 使用 ADB Lite(实验性功能) 退出时释放 ADB diff --git a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml index 036a4df158..3128f80506 100644 --- a/src/MaaWpfGui/Res/Localizations/zh-tw.xaml +++ b/src/MaaWpfGui/Res/Localizations/zh-tw.xaml @@ -144,6 +144,7 @@ 肉鴿在戰鬥結束前延遲「停止」動作 在第五層 BOSS 前暫停 滿級後自動停止 + 启用刷钱种子 暫停下幹員(同時影響肉鴿、自動戰鬥、保全)(不穩定,暫不推薦開啟) 使用 ADB Lite(實驗性功能) 退出時釋放 ADB diff --git a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs index f9a5571071..1119fbde48 100644 --- a/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/TaskQueueViewModel.cs @@ -1790,7 +1790,8 @@ namespace MaaWpfGui.ViewModels.UI SettingsViewModel.RoguelikeTask.RoguelikeTheme, SettingsViewModel.RoguelikeTask.RoguelikeRefreshTraderWithDice, SettingsViewModel.RoguelikeTask.RoguelikeStopAtFinalBoss, - SettingsViewModel.RoguelikeTask.RoguelikeStopAtMaxLevel); + SettingsViewModel.RoguelikeTask.RoguelikeStopAtMaxLevel, + SettingsViewModel.RoguelikeTask.RoguelikeStartWithSeed); } private static bool AppendReclamation() diff --git a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RoguelikeSettingsUserControlModel.cs b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RoguelikeSettingsUserControlModel.cs index 21d22a7e5a..594d747d86 100644 --- a/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RoguelikeSettingsUserControlModel.cs +++ b/src/MaaWpfGui/ViewModels/UserControl/TaskQueue/RoguelikeSettingsUserControlModel.cs @@ -704,4 +704,21 @@ public class RoguelikeSettingsUserControlModel : PropertyChangedBase ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeStopAtMaxLevel, value.ToString()); } } + + private bool _roguelikeStartWithSeedRaw = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.RoguelikeStartWithSeed, bool.FalseString)); + + /// + /// Gets or sets a value indicating whether start with seed when investing in Sarkaz. + /// + public bool RoguelikeStartWithSeedRaw + { + get => _roguelikeStartWithSeedRaw; + set + { + SetAndNotify(ref _roguelikeStartWithSeedRaw, value); + ConfigurationHelper.SetValue(ConfigurationKeys.RoguelikeStartWithSeed, value.ToString()); + } + } + + public bool RoguelikeStartWithSeed => _roguelikeStartWithSeedRaw && RoguelikeTheme == "Sarkaz" && RoguelikeMode == "1" && RoguelikeSquad is "点刺成锭分队" or "后勤分队"; } diff --git a/src/MaaWpfGui/Views/UserControl/TaskQueue/RoguelikeSettingsUserControl.xaml b/src/MaaWpfGui/Views/UserControl/TaskQueue/RoguelikeSettingsUserControl.xaml index 9e2c9440d0..56b55f6ccc 100644 --- a/src/MaaWpfGui/Views/UserControl/TaskQueue/RoguelikeSettingsUserControl.xaml +++ b/src/MaaWpfGui/Views/UserControl/TaskQueue/RoguelikeSettingsUserControl.xaml @@ -217,6 +217,15 @@ Text="{DynamicResource RoguelikeStopAtMaxLevel}" TextWrapping="Wrap" /> + + +