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 0000000000..b24bce5c43 Binary files /dev/null and b/resource/template/Battle/Plot/BattleAvatarDialog.png differ 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;