From f6c39c3a8f05ddcc3f537dbf3e8e6e481bb9a2c5 Mon Sep 17 00:00:00 2001 From: Status102 <102887808+status102@users.noreply.github.com> Date: Sat, 7 Mar 2026 00:30:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=88=E5=B9=B6=20=E5=A4=84=E4=BA=8E?= =?UTF-8?q?=E6=88=98=E6=96=97=E4=B8=AD=20=E6=A3=80=E6=B5=8B,=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=80=8D=E9=80=9F=E8=AE=B0=E5=BF=86,=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=88=98=E6=96=97=E4=B8=AD=20=E4=B8=8D=E5=B8=A6?= =?UTF-8?q?=E8=B7=B3=E8=BF=87=E6=8C=89=E9=92=AE=E7=9A=84=20=E5=B8=A6?= =?UTF-8?q?=E5=A4=B4=E5=83=8F=E5=AF=B9=E8=AF=9D=E6=95=99=E7=A8=8B=20(#1570?= =?UTF-8?q?6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * rft: 合并 处于战斗中 检测, 增加倍速记忆 * feat: 支持战斗中 不带跳过按钮的 带头像对话教程 * perf: 增加重试次数上限 * perf: 2倍速检查一致化 --- resource/tasks/tasks.json | 7 ++++ .../Battle/Plot/BattleAvatarDialog.png | Bin 0 -> 1829 bytes src/MaaCore/Task/BattleHelper.cpp | 37 +++++++++++++++++- src/MaaCore/Task/BattleHelper.h | 6 ++- .../Task/Miscellaneous/BattleProcessTask.cpp | 34 +++++----------- .../Task/Miscellaneous/BattleProcessTask.h | 2 - 6 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 resource/template/Battle/Plot/BattleAvatarDialog.png diff --git a/resource/tasks/tasks.json b/resource/tasks/tasks.json index 5fb8abd511..61115be0f4 100644 --- a/resource/tasks/tasks.json +++ b/resource/tasks/tasks.json @@ -3577,6 +3577,13 @@ "template": "SkipThePreBattlePlotConfirm.png", "next": ["EndOfPlot"] }, + "BattleAvatarDialog": { + "doc": "战斗中带头像对话框, 类似于 SkipThePreBattlePlot(可见于画中人关卡) 的, 但是缺少 跳过 按钮", + "action": "ClickSelf", + "roi": [70, 30, 120, 30], + "next": ["BattleAvatarDialog", "Stop"], + "rectMove": [125, 20, 200, 60] + }, "EndOfPlot": { "roi": [520, 0, 243, 206], "action": "ClickRect", diff --git a/resource/template/Battle/Plot/BattleAvatarDialog.png b/resource/template/Battle/Plot/BattleAvatarDialog.png new file mode 100644 index 0000000000000000000000000000000000000000..b24bce5c4303ab0eb27b07eda6970d8b0e446d38 GIT binary patch literal 1829 zcmV+=2io|FP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2D(W^K~z{r&6rtF zR7n)aPv33?caU9;+pq}44TvUc!jlii2S0$u&%$>BpG}6BAprw%jYiOMizp~4t1Rxa z2tD;X_nxM_G|rez()_i!b*oODs)hHB48|R zJOcNRF{5|Vxc7($4GAZ-(^ZFiy(kpzEthdKcYKpom zD=V_Fu%P@xrG^u~FmVQIvR~EMTL}>ma5Pw7^TM>v|G1sm2KO$ zNq&BQMhJ}JM*!nnwro+_yu7@1`LTv5fDV4p(Xx%fhcO!Kvhj=4agJZnm6ergvq;=X zNK{o-rBkVt96WeXnwy(-aD04RW~OIU2#jY+N0>v04oPEUqo%bRH*UzCJ9o728;L&r zE?v5$#(ehdnMT;s;!>ENA{)Y+^m*pY8I9PfsVTX2>z1xLd-kkGA7{CJ`?fmFv17;N zz<~oAIXyi+^8NewkWmEo#>t@LoJ&hf^5DS(jS!4sXXJ^@IAVEuxzgRge_!6deVaMI z(dG)2fMii&VJink=u@Xoskim@^~u9W5B0F4qoXo5Hm1+_@84_0P?NyqTOD@bIvVkBw*ejgF1V=g*&|uC7k`PEJfp=U<(=Pknv8?AWnG zX*)Z^vAuiuYIIX`I{xgCp`jt2w+2t@$eulWln$ley?a*;ge({uI(5F88Fh%0Cr`?* zUAtstWJLEcBj(yT?4R7Zb7w0NfiNhY!7pFFs0R}6m6erJSy3q!l@(ft_V3@XNph(~h+yLa!NbaizptqH;!E&-&z3l}bE|LfPU+AwGwL>Wp#`9xS-TbrgF zE))Cq?bCGF-rlZb@PjXFFdAt$4)~BNsds?0`H^j4?YnpHWnxLbgC4u#@xcyzN$amg&;4Li5w0{0Vg+G{#DY*04SPbjbP+%YR<&Og!K3K zD{WI#lN1*hs}ZRifLin7#S5(gsxJV~J08?splj`Ub}Wp4F^B}j1+aEhsZKnNWVA{ zmja{1q2S-r(xP<_15Qs*t8vUQxik)YuYR(7&ueq7k*4AqNMp;~o zt;QHXelCgg@_#ijWK#-b{`eX`Uh`plV_cgzUOvB#22K_bHFjWw3AA1Vq!zr9^n$mZ zK7CrR;uwn}OPb51v8btn*e}|Xr~msFus!VE=IkBNhsIa9{~o7h+^4nvMh3qL2H}r` ztBSBE&4h_J<}7lE5~76QM_*MW@i#WtV~QrpEcdE8^JIjl}gD!nK@87 TUc{H100000NkvXXu0mjfStg3Q literal 0 HcmV?d00001 diff --git a/src/MaaCore/Task/BattleHelper.cpp b/src/MaaCore/Task/BattleHelper.cpp index caa9bdb3f9..28d6deeb21 100644 --- a/src/MaaCore/Task/BattleHelper.cpp +++ b/src/MaaCore/Task/BattleHelper.cpp @@ -618,7 +618,20 @@ bool asst::BattleHelper::check_skip_plot_button(const cv::Mat& reusable) return ret; } -bool asst::BattleHelper::check_in_speed_up(const cv::Mat& reusable) +bool asst::BattleHelper::check_avatar_dialog(const cv::Mat& reusable) +{ + cv::Mat image = reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable; + + Matcher battle_plot_analyzer(image); + battle_plot_analyzer.set_task_info("BattleAvatarDialog"); + bool ret = battle_plot_analyzer.analyze().has_value(); + if (ret) { + ProcessTask(this_task(), { "BattleAvatarDialog" }).run(); + } + return ret; +} + +bool asst::BattleHelper::check_in_speedup(const cv::Mat& reusable) { cv::Mat image = reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable; Matcher analyzer(image); @@ -631,7 +644,27 @@ bool asst::BattleHelper::check_in_battle(const cv::Mat& reusable, bool weak) cv::Mat image = reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable; if (weak) { BattlefieldMatcher analyzer(image); - m_in_battle = analyzer.analyze().has_value(); + auto result = analyzer.analyze(); + m_in_battle = result.has_value(); + if (m_in_battle && !result->pause_button) { + if (check_skip_plot_button(image)) { + if (m_in_speedup && !check_in_speedup()) { + speed_up(); // 跳过剧情会退出2倍速 + } + } + else if (check_avatar_dialog(image)) { + if (m_in_speedup && !check_in_speedup()) { + speed_up(); // 跳过剧情会退出2倍速 + m_inst_helper.sleep(Config.get_options().task_delay); + int times = 0; + while (times < 20 && !m_inst_helper.need_exit() && !check_in_speedup()) { + speed_up(); // 跳过剧情会退出2倍速 + m_inst_helper.sleep(Config.get_options().task_delay); + times++; + } + } + } + } } else { check_skip_plot_button(image); diff --git a/src/MaaCore/Task/BattleHelper.h b/src/MaaCore/Task/BattleHelper.h index 955c8dd626..a521b123b3 100644 --- a/src/MaaCore/Task/BattleHelper.h +++ b/src/MaaCore/Task/BattleHelper.h @@ -67,7 +67,10 @@ protected: bool use_skill(const Point& loc, bool keep_waiting = true); bool check_pause_button(const cv::Mat& reusable = cv::Mat()); bool check_skip_plot_button(const cv::Mat& reusable = cv::Mat()); - bool check_in_speed_up(const cv::Mat& reusable = cv::Mat()); + // 检查是否有战斗中带头像的对话框 + bool check_avatar_dialog(const cv::Mat& reusable = cv::Mat()); + // 检查是否处于二倍速 + bool check_in_speedup(const cv::Mat& reusable = cv::Mat()); virtual bool check_in_battle(const cv::Mat& reusable = cv::Mat(), bool weak = true); virtual bool wait_until_start(bool weak = true); bool wait_until_end(bool weak = true); @@ -115,6 +118,7 @@ protected: std::unordered_map m_skill_error_count; std::unordered_map m_last_use_skill_time; int m_camera_count = 0; + bool m_in_speedup = false; // 是否处于2倍速 std::pair m_camera_shift = { 0., 0. }; /* 实时更新的数据 */ diff --git a/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp index 5823185416..8abbcc9976 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp +++ b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp @@ -238,6 +238,9 @@ bool asst::BattleProcessTask::do_action(const battle::copilot::Action& action, s case ActionType::SwitchSpeed: ret = speed_up(); + if (ret) { + m_in_speedup = !m_in_speedup; + } break; case ActionType::BulletTime: @@ -480,31 +483,12 @@ void asst::BattleProcessTask::sleep_and_do_strategy(unsigned millisecond) const auto start = std::chrono::steady_clock::now(); const auto delay = millisecond * 1ms; - while (!need_exit() && std::chrono::steady_clock::now() - start < delay) { - do_strategic_action(); + + cv::Mat image = ctrler()->get_image(); + while (!need_exit() && check_in_battle(image) && std::chrono::steady_clock::now() - start < delay) { + do_strategic_action(image); std::this_thread::yield(); + + image = ctrler()->get_image(); } } - -bool asst::BattleProcessTask::check_in_battle(const cv::Mat& reusable, bool weak) -{ - LogTraceFunction; - - cv::Mat image = reusable.empty() ? ctrler()->get_image() : reusable; - - if (weak) { - BattlefieldMatcher analyzer(image); - auto result = analyzer.analyze(); - m_in_battle = result.has_value(); - if (m_in_battle && !result->pause_button) { - if (check_skip_plot_button(image) && check_in_speed_up(image)) { - speed_up(); - } - } - } - else { - check_skip_plot_button(image); - m_in_battle = check_pause_button(image); - } - return m_in_battle; -} diff --git a/src/MaaCore/Task/Miscellaneous/BattleProcessTask.h b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.h index f819c6563f..05ce2e235b 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleProcessTask.h +++ b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.h @@ -44,8 +44,6 @@ protected: bool enter_bullet_time(const std::string& name, const Point& location); void sleep_and_do_strategy(unsigned millisecond); - virtual bool check_in_battle(const cv::Mat& reusable = cv::Mat(), bool weak = true) override; - battle::copilot::CombatData m_combat_data; std::unordered_map m_oper_in_group;