diff --git a/resource/roguelike_recruit.json b/resource/roguelike_recruit.json index 7bf55969c1..0b4ab27b0e 100644 --- a/resource/roguelike_recruit.json +++ b/resource/roguelike_recruit.json @@ -10,17 +10,17 @@ "Support" ], "Warrior": [ - { - "name": "帕拉斯", - "level": 6, - "skill": 1 - }, { "name": "山", "level": 6, "skill": 2, "skill_usage": 2 }, + { + "name": "帕拉斯", + "level": 6, + "skill": 1 + }, { "name": "棘刺", "level": 6, diff --git a/resource/tasks.json b/resource/tasks.json index 2e00ad96aa..a061b48402 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -4578,11 +4578,12 @@ "BattleOperName": { "algorithm": "OcrDetect", "text": [], + "fullMatch": true, "roi": [ 0, + 182, 160, - 180, - 60 + 30 ] }, "BattleWaitingToLoad": { @@ -6238,10 +6239,10 @@ "Roguelike1SkillSelectionRect": { "template": "empty.png", "roi": [ - 171, + 170, 2, 170, - 3 + 2 ], "rectMove": [ 5, diff --git a/src/MeoAssistant/BattleImageAnalyzer.h b/src/MeoAssistant/BattleImageAnalyzer.h index dac9899491..37be6dc96f 100644 --- a/src/MeoAssistant/BattleImageAnalyzer.h +++ b/src/MeoAssistant/BattleImageAnalyzer.h @@ -19,7 +19,7 @@ namespace asst Cost = 32, // 费用 Vacancies = 64, // 剩余可部署干员数 // 肉鸽模式需要用到的识别 - Roguelike = Home | HP | Oper | Skill + Roguelike = Home | Oper }; public: using AbstractImageAnalyzer::AbstractImageAnalyzer; diff --git a/src/MeoAssistant/BattleProcessTask.cpp b/src/MeoAssistant/BattleProcessTask.cpp index 7b3da759f2..aa36d357eb 100644 --- a/src/MeoAssistant/BattleProcessTask.cpp +++ b/src/MeoAssistant/BattleProcessTask.cpp @@ -11,7 +11,7 @@ #include "ProcessTask.h" #include "MatchImageAnalyzer.h" -#include "OcrImageAnalyzer.h" +#include "OcrWithPreprocessImageAnalyzer.h" #include "BattleImageAnalyzer.h" void asst::BattleProcessTask::set_stage_name(std::string name) @@ -128,7 +128,7 @@ bool asst::BattleProcessTask::analyze_opers_preview() auto image = m_ctrler->get_image(); - OcrImageAnalyzer name_analyzer(image); + OcrWithPreprocessImageAnalyzer name_analyzer(image); name_analyzer.set_task_info("BattleOperName"); name_analyzer.set_replace( std::dynamic_pointer_cast( @@ -239,7 +239,7 @@ bool asst::BattleProcessTask::update_opers_info(const cv::Mat& image) m_ctrler->click(cur_oper.rect); sleep(Task.get("BattleUseOper")->pre_delay); - OcrImageAnalyzer name_analyzer(m_ctrler->get_image()); + OcrWithPreprocessImageAnalyzer name_analyzer(m_ctrler->get_image()); name_analyzer.set_task_info("BattleOperName"); name_analyzer.set_replace( std::dynamic_pointer_cast( @@ -478,10 +478,11 @@ bool asst::BattleProcessTask::use_skill(const BattleAction& action) bool asst::BattleProcessTask::try_possible_skill(const cv::Mat& image) { - static const Rect& skill_roi_move = Task.get("BattleAutoSkillFlag")->rect_move; + auto task_ptr = Task.get("BattleAutoSkillFlag"); + const Rect& skill_roi_move = task_ptr->rect_move; MatchImageAnalyzer analyzer(image); - analyzer.set_task_info("BattleAutoSkillFlag"); + analyzer.set_task_info(task_ptr); bool used = false; for (auto& [name, info] : m_used_opers) { if (info.info.skill_usage != BattleSkillUsage::Possibly diff --git a/src/MeoAssistant/MeoAssistant.vcxproj b/src/MeoAssistant/MeoAssistant.vcxproj index 4211ab2203..98433fb52c 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj +++ b/src/MeoAssistant/MeoAssistant.vcxproj @@ -195,7 +195,7 @@ DynamicLibrary false - v143 + v142 true Unicode diff --git a/src/MeoAssistant/OcrImageAnalyzer.h b/src/MeoAssistant/OcrImageAnalyzer.h index 43e28804ce..0e606f7876 100644 --- a/src/MeoAssistant/OcrImageAnalyzer.h +++ b/src/MeoAssistant/OcrImageAnalyzer.h @@ -27,8 +27,8 @@ namespace asst void set_required(std::vector required, bool full_match = false) noexcept; void set_replace(std::unordered_map replace) noexcept; - void set_task_info(std::shared_ptr task_ptr); - void set_task_info(const std::string& task_name); + virtual void set_task_info(std::shared_ptr task_ptr); + virtual void set_task_info(const std::string& task_name); virtual void set_use_cache(bool is_use) noexcept; virtual void set_region_of_appeared(Rect region) noexcept; diff --git a/src/MeoAssistant/OcrWithPreprocessImageAnalyzer.cpp b/src/MeoAssistant/OcrWithPreprocessImageAnalyzer.cpp index 2bc79ecc39..b0a35fc7dd 100644 --- a/src/MeoAssistant/OcrWithPreprocessImageAnalyzer.cpp +++ b/src/MeoAssistant/OcrWithPreprocessImageAnalyzer.cpp @@ -49,6 +49,16 @@ void asst::OcrWithPreprocessImageAnalyzer::set_expansion(int expansion) m_expansion = expansion; } +void asst::OcrWithPreprocessImageAnalyzer::set_task_info(std::shared_ptr task_ptr) +{ + OcrImageAnalyzer::set_task_info(task_ptr); +} + +void asst::OcrWithPreprocessImageAnalyzer::set_task_info(const std::string& task_name) +{ + OcrImageAnalyzer::set_task_info(task_name); +} + void asst::OcrWithPreprocessImageAnalyzer::set_task_info(OcrTaskInfo task_info) noexcept { m_required = std::move(task_info.text); diff --git a/src/MeoAssistant/OcrWithPreprocessImageAnalyzer.h b/src/MeoAssistant/OcrWithPreprocessImageAnalyzer.h index f1eeee46f6..f6cbbbcec8 100644 --- a/src/MeoAssistant/OcrWithPreprocessImageAnalyzer.h +++ b/src/MeoAssistant/OcrWithPreprocessImageAnalyzer.h @@ -15,9 +15,10 @@ namespace asst void set_split(bool split); void set_expansion(int expansion); - virtual void set_task_info(OcrTaskInfo task_info) noexcept override; - + virtual void set_task_info(std::shared_ptr task_ptr); + virtual void set_task_info(const std::string& task_name); protected: + virtual void set_task_info(OcrTaskInfo task_info) noexcept override; int m_threshold_lower = 140; int m_threshold_upper = 255; diff --git a/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp b/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp index 333ba88524..c443f937b2 100644 --- a/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeBattleTaskPlugin.cpp @@ -6,9 +6,11 @@ #include "Controller.h" #include "TaskData.h" #include "ProcessTask.h" -#include "OcrImageAnalyzer.h" +#include "OcrWithPreprocessImageAnalyzer.h" #include "Resource.h" #include "Logger.hpp" +#include "RuntimeStatus.h" +#include "MatchImageAnalyzer.h" bool asst::RoguelikeBattleTaskPlugin::verify(AsstMsg msg, const json::value& details) const { @@ -40,6 +42,12 @@ bool asst::RoguelikeBattleTaskPlugin::_run() return true; } + if (!wait_start()) { + return false; + } + + speed_up(); + constexpr static auto time_limit = std::chrono::minutes(10); bool timeout = false; @@ -153,13 +161,6 @@ bool asst::RoguelikeBattleTaskPlugin::auto_battle() using BattleRealTimeOper = asst::BattleRealTimeOper; - BattleImageAnalyzer battle_analyzer(m_ctrler->get_image()); - battle_analyzer.set_target(BattleImageAnalyzer::Target::Roguelike); - - if (!battle_analyzer.analyze()) { - return false; - } - //if (int hp = battle_analyzer.get_hp(); // hp != 0) { // bool used_skills = false; @@ -177,31 +178,17 @@ bool asst::RoguelikeBattleTaskPlugin::auto_battle() // } //} - //for (const Rect& rect : battle_analyzer.get_ready_skills()) { - // // 找出这个可以使用的技能是哪个干员的(根据之前放干员的位置) - // std::string name = "NotFound"; - // for (const auto& [loc, oper_name] : m_used_tiles) { - // auto point = m_normal_tile_info[loc].pos; - // if (rect.include(point)) { - // name = oper_name; - // break; - // } - // } + const cv::Mat& image = m_ctrler->get_image(); + if (try_possible_skill(image)) { + return true; + } - // auto& usage = m_skill_usage[name]; - // Log.info("Oper", name, ", skill usage", static_cast(usage)); - // switch (usage) { - // case BattleSkillUsage::Once: - // use_skill(rect); - // usage = BattleSkillUsage::OnceUsed; - // return true; - // break; - // case BattleSkillUsage::Possibly: - // use_skill(rect); - // return true; - // break; - // } - //} + BattleImageAnalyzer battle_analyzer(image); + battle_analyzer.set_target(BattleImageAnalyzer::Target::Roguelike); + + if (!battle_analyzer.analyze()) { + return false; + } const auto& opers = battle_analyzer.get_opers(); if (opers.empty()) { @@ -246,7 +233,7 @@ bool asst::RoguelikeBattleTaskPlugin::auto_battle() m_ctrler->click(opt_oper.rect); sleep(use_oper_task_ptr->pre_delay); - OcrImageAnalyzer oper_name_analyzer(m_ctrler->get_image()); + OcrWithPreprocessImageAnalyzer oper_name_analyzer(m_ctrler->get_image()); oper_name_analyzer.set_task_info("BattleOperName"); oper_name_analyzer.set_replace( std::dynamic_pointer_cast( @@ -295,8 +282,8 @@ bool asst::RoguelikeBattleTaskPlugin::auto_battle() Point placed_loc = get_placed(loc); Point placed_point = m_side_tile_info.at(placed_loc).pos; #ifdef ASST_DEBUG - auto image = m_ctrler->get_image(); - cv::circle(image, cv::Point(placed_point.x, placed_point.y), 10, cv::Scalar(0, 0, 255), -1); + auto draw_image = m_ctrler->get_image(); + cv::circle(draw_image, cv::Point(placed_point.x, placed_point.y), 10, cv::Scalar(0, 0, 255), -1); #endif Rect placed_rect(placed_point.x, placed_point.y, 1, 1); m_ctrler->swipe(opt_oper.rect, placed_rect, swipe_oper_task_ptr->pre_delay); @@ -372,11 +359,66 @@ void asst::RoguelikeBattleTaskPlugin::clear() m_side_tile_info.clear(); m_used_tiles.clear(); - //for (auto& [_, usage] : m_skill_usage) { - // if (usage == BattleSkillUsage::OnceUsed) { - // usage = BattleSkillUsage::Once; - // } - //} + for (auto& [key, status] : m_restore_status) { + m_status->set_data(key, status); + } + m_restore_status.clear(); +} + +bool asst::RoguelikeBattleTaskPlugin::try_possible_skill(const cv::Mat& image) +{ + auto task_ptr = Task.get("BattleAutoSkillFlag"); + const Rect& skill_roi_move = task_ptr->rect_move; + + MatchImageAnalyzer analyzer(image); + analyzer.set_task_info(task_ptr); + bool used = false; + for (auto& [loc, name] : m_used_tiles) { + std::string status_key = "RoguelikeSkillUsage-" + name; + BattleSkillUsage usage = BattleSkillUsage::Possibly; + auto usage_opt = m_status->get_data(status_key); + if (usage_opt) { + usage = static_cast(usage_opt.value()); + } + + if (usage != BattleSkillUsage::Possibly + && usage != BattleSkillUsage::Once) { + continue; + } + const Point pos = m_normal_tile_info.at(loc).pos; + const Rect pos_rect(pos.x, pos.y, 1, 1); + const Rect roi = pos_rect.move(skill_roi_move); + analyzer.set_roi(roi); + if (!analyzer.analyze()) { + continue; + } + m_ctrler->click(pos_rect); + used |= ProcessTask(*this, { "BattleSkillReadyOnClick" }).set_task_delay(0).run(); + if (usage == BattleSkillUsage::Once) { + m_status->set_data(status_key, static_cast(BattleSkillUsage::OnceUsed)); + m_restore_status[status_key] = static_cast(BattleSkillUsage::Once); + } + } + return used; +} + +bool asst::RoguelikeBattleTaskPlugin::wait_start() +{ + BattleImageAnalyzer oper_analyzer; + oper_analyzer.set_target(BattleImageAnalyzer::Target::Oper); + + while (!need_exit()) { + oper_analyzer.set_image(m_ctrler->get_image()); + if (oper_analyzer.analyze()) { + break; + } + std::this_thread::yield(); + } + + // 干员头像出来之后,还要过 2 秒左右才可以点击,这里要加个延时 + sleep(Task.get("BattleWaitingToLoad")->rear_delay); + + return true; } //asst::Rect asst::RoguelikeBattleTaskPlugin::get_placed_by_cv() diff --git a/src/MeoAssistant/RoguelikeBattleTaskPlugin.h b/src/MeoAssistant/RoguelikeBattleTaskPlugin.h index 2d56f4d580..c52bb1d7d1 100644 --- a/src/MeoAssistant/RoguelikeBattleTaskPlugin.h +++ b/src/MeoAssistant/RoguelikeBattleTaskPlugin.h @@ -29,6 +29,8 @@ namespace asst bool use_skill(const Rect& rect); bool retreat(const Point& point); void clear(); + bool try_possible_skill(const cv::Mat& image); + bool wait_start(); // 通过资源文件离线计算可放置干员的位置,优先使用 // 返回 可格子的位置 @@ -46,6 +48,7 @@ namespace asst std::vector m_homes; size_t m_cur_home_index = 0; std::unordered_map m_used_tiles; + std::unordered_map m_restore_status; std::string m_stage_name; }; diff --git a/src/MeoAssistant/RoguelikeSkillSelectionImageAnalyzer.cpp b/src/MeoAssistant/RoguelikeSkillSelectionImageAnalyzer.cpp index 6906bb068d..58118f14fc 100644 --- a/src/MeoAssistant/RoguelikeSkillSelectionImageAnalyzer.cpp +++ b/src/MeoAssistant/RoguelikeSkillSelectionImageAnalyzer.cpp @@ -38,7 +38,7 @@ std::string asst::RoguelikeSkillSelectionImageAnalyzer::name_analyze(const Rect& { OcrWithPreprocessImageAnalyzer analyzer; auto name_task_ptr = std::dynamic_pointer_cast(Task.get("Roguelike1SkillSelectionName")); - analyzer.set_task_info(*name_task_ptr); + analyzer.set_task_info(name_task_ptr); analyzer.set_image(m_image, roi.move(name_task_ptr->roi)); analyzer.set_required(Resrc.roguelike_recruit().get_oper_order()); analyzer.set_replace( diff --git a/src/MeoAssistant/RoguelikeSkillSelectionTaskPlugin.cpp b/src/MeoAssistant/RoguelikeSkillSelectionTaskPlugin.cpp index 50b8610c92..4f597e2e5f 100644 --- a/src/MeoAssistant/RoguelikeSkillSelectionTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeSkillSelectionTaskPlugin.cpp @@ -4,6 +4,7 @@ #include "Controller.h" #include "TaskData.h" #include "Resource.h" +#include "RuntimeStatus.h" #include "Logger.hpp" @@ -35,16 +36,20 @@ bool asst::RoguelikeSkillSelectionTaskPlugin::_run() for (const auto& [name, skill_vec] : analyzer.get_result()) { const auto& oper_info = rg_src.get_oper_info(name); int index = 0; + BattleSkillUsage usage = BattleSkillUsage::Possibly; if (skill_vec.size() >= oper_info.skill) { index = oper_info.skill - 1; + usage = oper_info.skill_usage; } else if (skill_vec.size() >= oper_info.alternate_skill) { index = oper_info.alternate_skill - 1; + usage = oper_info.alternate_skill_usage; } if (index) { m_ctrler->click(skill_vec.at(index)); } + m_status->set_data("RoguelikeSkillUsage-" + name, static_cast(usage)); } return true;