From 9916e45288dbb2c032938db0d43f0ae13745ebf4 Mon Sep 17 00:00:00 2001 From: et Date: Sat, 13 Aug 2022 23:47:21 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E8=82=89?= =?UTF-8?q?=E9=B8=BD=E6=8B=9B=E5=8B=9F=E7=95=8C=E9=9D=A2=E4=B8=93=E7=94=A8?= =?UTF-8?q?=E6=BB=91=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resource/tasks.json | 47 +++++++++++++++++++ .../RoguelikeRecruitTaskPlugin.cpp | 44 +++++++++++++++-- src/MeoAssistant/RoguelikeRecruitTaskPlugin.h | 2 + 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/resource/tasks.json b/resource/tasks.json index 34a6c7a3be..fc008e94a0 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -4373,6 +4373,53 @@ 300 ] }, + "RoguelikeRecruitSwipeToTheLeftBegin": { + "algorithm": "JustReturn", + "action": "ClickRect", + "specificRect": [ + 1080, + 200, + 100, + 300 + ], + "preDelay": 300, + "rearDelay": 1000, + "maxTimes": 2, + "Doc": "这里的preDelay作为滑动duration使用,rearDelay作为滑动额外延时使用,maxTimes作为重复次数使用" + }, + "RoguelikeRecruitSwipeToTheLeftEnd": { + "algorithm": "JustReturn", + "action": "ClickRect", + "specificRect": [ + 400, + 200, + 100, + 300 + ] + }, + "RoguelikeRecruitSlowlySwipeRightRect": { + "algorithm": "JustReturn", + "action": "ClickRect", + "specificRect": [ + 780, + 200, + 100, + 300 + ], + "preDelay": 1500, + "rearDelay": 300, + "Doc": "这里的preDelay作为滑动duration使用,rearDelay作为滑动额外延时使用" + }, + "RoguelikeRecruitSlowlySwipeLeftRect": { + "algorithm": "JustReturn", + "action": "ClickRect", + "specificRect": [ + 360, + 200, + 100, + 300 + ] + }, "InfrastOperMoodProgressBar": { "template": "empty.png", "templThreshold": 160, diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index 41fdfafa57..cda7b61276 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -107,7 +107,7 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() } Log.info(__FUNCTION__, "did not choose oper."); - ProcessTask(*this, { "SwipeToTheLeft" }).set_times_limit("SwipeToTheLeft", i / 2 + 1).run(); + swipe_to_the_left_of_operlist(i / 2 + 1); return false; } @@ -144,7 +144,7 @@ bool asst::RoguelikeRecruitTaskPlugin::check_core_char() } Log.info(__FUNCTION__, "| Oper list:", oper_names); if (it == chars.cend()) { - ProcessTask(*this, { "SlowlySwipeToTheRight" }).run(); + slowly_swipe(ProcessTaskAction::SlowlySwipeToTheRight); sleep(Task.get("Roguelike1Custom-HijackSquad")->rear_delay); continue; } @@ -152,7 +152,7 @@ bool asst::RoguelikeRecruitTaskPlugin::check_core_char() return true; } Log.info(__FUNCTION__, "| Cannot find oper `" + core_opt.value() + "`"); - ProcessTask(*this, { "SwipeToTheLeft" }).run(); + swipe_to_the_left_of_operlist(); return false; } @@ -173,3 +173,41 @@ void asst::RoguelikeRecruitTaskPlugin::select_oper(const BattleRecruitOperInfo& }; m_status->set_str(RuntimeStatus::RoguelikeCharOverview, overview.to_string()); } + +void asst::RoguelikeRecruitTaskPlugin::swipe_to_the_left_of_operlist(int loop_times) +{ + LogTraceFunction; + static Rect begin_rect = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->specific_rect; + static Rect end_rect = Task.get("RoguelikeRecruitSwipeToTheLeftEnd")->specific_rect; + static int duration = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->pre_delay; + static int extra_delay = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->rear_delay; + static int cfg_loop_times = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->max_times; + + for (int i = 0; i != cfg_loop_times * loop_times; ++i) { + if (need_exit()) { + return; + } + m_ctrler->swipe(end_rect, begin_rect, duration, true, 0, false); + } + sleep(extra_delay); +} + +void asst::RoguelikeRecruitTaskPlugin::slowly_swipe(ProcessTaskAction action) +{ + LogTraceFunction; + static Rect right_rect = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->specific_rect; + static Rect left_rect = Task.get("RoguelikeRecruitSlowlySwipeLeftRect")->specific_rect; + static int duration = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->pre_delay; + static int extra_delay = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->rear_delay; + + switch (action) { + case asst::ProcessTaskAction::SlowlySwipeToTheLeft: + m_ctrler->swipe(left_rect, right_rect, duration, true, extra_delay, true); + break; + case asst::ProcessTaskAction::SlowlySwipeToTheRight: + m_ctrler->swipe(right_rect, left_rect, duration, true, extra_delay, true); + break; + default: // 走不到这里 + break; + } +} diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h index 031221a6dd..9174671425 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h @@ -15,6 +15,8 @@ namespace asst protected: virtual bool _run() override; + void swipe_to_the_left_of_operlist(int loop_times = 1); // 滑动到干员列表的最左侧 + void slowly_swipe(ProcessTaskAction action); // 缓慢向干员列表的左侧/右侧滑动 private: bool check_core_char(); From 6e475ccd4ecefdca7ddf695f6432d12695e0753b Mon Sep 17 00:00:00 2001 From: et Date: Sun, 14 Aug 2022 21:51:05 +0800 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=E8=82=89=E9=B8=BD=E6=8B=9B?= =?UTF-8?q?=E5=8B=9F=E6=94=AF=E6=8C=81=E8=B7=A8=E8=81=8C=E4=B8=9A=E4=BC=98?= =?UTF-8?q?=E5=85=88=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resource/roguelike_recruit.json | 244 ++++++++++---- src/MeoAssistant/RoguelikeRecruitConfiger.cpp | 3 + src/MeoAssistant/RoguelikeRecruitConfiger.h | 3 + .../RoguelikeRecruitTaskPlugin.cpp | 305 ++++++++++++------ src/MeoAssistant/RoguelikeRecruitTaskPlugin.h | 9 + 5 files changed, 408 insertions(+), 156 deletions(-) diff --git a/resource/roguelike_recruit.json b/resource/roguelike_recruit.json index a0d6b07811..e5acb28cad 100644 --- a/resource/roguelike_recruit.json +++ b/resource/roguelike_recruit.json @@ -13,270 +13,394 @@ "Warrior": [ { "name": "帕拉斯", - "skill": 1 + "skill": 1, + "recruit_priority": 900, + "promote_priority": 850 }, { "name": "Sharp", - "skill": 1 + "skill": 1, + "recruit_priority": 650, + "promote_priority": 600 }, { "name": "艾丽妮", - "skill": 1 + "skill": 1, + "recruit_priority": 800, + "promote_priority": 750 }, { "name": "煌", - "skill": 2 + "skill": 2, + "recruit_priority": 700, + "promote_priority": 650 }, { "name": "山", "skill": 2, - "skill_usage": 2 + "skill_usage": 2, + "recruit_priority": 700, + "promote_priority": 650 }, { "name": "羽毛笔", - "skill": 1 + "skill": 1, + "recruit_priority": 600, + "promote_priority": 550 }, { "name": "银灰", "skill": 3, - "alternate_skill": 1 + "alternate_skill": 1, + "recruit_priority": 500, + "promote_priority": 800 }, { "name": "陈", - "skill": 2 + "skill": 2, + "recruit_priority": 500, + "promote_priority": 600 }, { "name": "拉普兰德", - "skill": 2 + "skill": 2, + "recruit_priority": 450, + "promote_priority": 400 }, { "name": "幽灵鲨", - "skill": 2 + "skill": 2, + "recruit_priority": 450, + "promote_priority": 400 }, { "name": "龙舌兰", - "skill": 1 + "skill": 1, + "recruit_priority": 400, + "promote_priority": 400 }, { "name": "星极", - "skill": 2 + "skill": 2, + "recruit_priority": 400, + "promote_priority": 400 }, { "name": "棘刺", "skill": 3, - "alternate_skill": 1 + "alternate_skill": 1, + "recruit_priority": 350, + "promote_priority": 1000 }, { "name": "柏喙", - "skill": 2 + "skill": 2, + "recruit_priority": 350, + "promote_priority": 300 }, { "name": "泡普卡", - "skill": 1 + "skill": 1, + "recruit_priority": 10, + "promote_priority": 0 }, { "name": "月见夜", - "skill": 1 + "skill": 1, + "recruit_priority": 10, + "promote_priority": 0 }, { "name": "玫兰莎", - "skill": 1 + "skill": 1, + "recruit_priority": 10, + "promote_priority": 0 } ], "Pioneer": [ { "name": "风笛", - "skill": 2 + "skill": 2, + "recruit_priority": 600, + "promote_priority": 500 }, { "name": "芬", - "skill": 1 + "skill": 1, + "recruit_priority": 200, + "promote_priority": 0 }, { "name": "桃金娘", - "skill": 1 + "skill": 1, + "recruit_priority": 200, + "promote_priority": 550 }, { "name": "翎羽", - "skill": 1 + "skill": 1, + "recruit_priority": 10, + "promote_priority": 0 } ], "Tank": [ { "name": "泥岩", - "skill": 2 + "skill": 2, + "recruit_priority": 750, + "promote_priority": 650 }, { "name": "塞雷娅", - "skill": 2 + "skill": 2, + "recruit_priority": 800, + "promote_priority": 650 }, { "name": "斑点", - "skill": 1 + "skill": 1, + "recruit_priority": 100, + "promote_priority": 0 }, { "name": "卡缇", - "skill": 1 + "skill": 1, + "recruit_priority": 80, + "promote_priority": 0 } ], "Sniper": [ { "name": "假日威龙陈", "skill": 3, - "alternate_skill": 1 + "alternate_skill": 1, + "recruit_priority": 900, + "promote_priority": 900 }, { "name": "Stormeye", - "skill": 1 + "skill": 1, + "recruit_priority": 750, + "promote_priority": 650 }, { "name": "能天使", "skill": 3, - "alternate_skill": 1 + "alternate_skill": 1, + "recruit_priority": 700, + "promote_priority": 650 }, { "name": "空弦", - "skill": 1 + "skill": 1, + "recruit_priority": 650, + "promote_priority": 600 }, { "name": "克洛丝", - "skill": 1 + "skill": 1, + "recruit_priority": 150, + "promote_priority": 0 }, { "name": "安德切尔", - "skill": 1 + "skill": 1, + "recruit_priority": 100, + "promote_priority": 0 }, { "name": "空爆", - "skill": 1 + "skill": 1, + "recruit_priority": 80, + "promote_priority": 0 } ], "Caster": [ { "name": "澄闪", "skill": 3, - "alternate_skill": 2 + "alternate_skill": 2, + "recruit_priority": 700, + "promote_priority": 800 }, { "name": "Pith", - "skill": 1 + "skill": 1, + "recruit_priority": 600, + "promote_priority": 600 }, { "name": "艾雅法拉", - "skill": 2 + "skill": 2, + "recruit_priority": 600, + "promote_priority": 600 }, { "name": "阿米娅", - "skill": 1 + "skill": 1, + "recruit_priority": 500, + "promote_priority": 500 }, { "name": "史都华德", - "skill": 1 + "skill": 1, + "recruit_priority": 100, + "promote_priority": 0 }, { "name": "炎熔", - "skill": 1 + "skill": 1, + "recruit_priority": 80, + "promote_priority": 0 } ], "Special": [ { "name": "归溟幽灵鲨", - "skill": 2 + "skill": 2, + "recruit_priority": 700, + "promote_priority": 700 }, { "name": "孑", - "skill": 2 + "skill": 2, + "recruit_priority": 80, + "promote_priority": 600 } ], "Medic": [ { "name": "凯尔希", "skill": 3, - "alternate_skill": 2 + "alternate_skill": 2, + "recruit_priority": 650, + "promote_priority": 600 }, { "name": "Touch", - "skill": 1 + "skill": 1, + "recruit_priority": 600, + "promote_priority": 500 }, { "name": "夜莺", - "skill": 2 + "skill": 2, + "recruit_priority": 550, + "promote_priority": 450 }, { "name": "白面鸮", - "skill": 2 + "skill": 2, + "recruit_priority": 550, + "promote_priority": 450 }, { "name": "桑葚", - "skill": 1 + "skill": 1, + "recruit_priority": 500, + "promote_priority": 400 }, { "name": "蜜莓", - "skill": 1 + "skill": 1, + "recruit_priority": 700, + "promote_priority": 1 }, { "name": "苏苏洛", - "skill": 2 + "skill": 2, + "recruit_priority": 500, + "promote_priority": 400 }, { "name": "调香师", - "skill": 1 + "skill": 1, + "recruit_priority": 700, + "promote_priority": 650 }, { "name": "安赛尔", - "skill": 1 + "skill": 1, + "recruit_priority": 100, + "promote_priority": 0 }, { "name": "芙蓉", - "skill": 1 + "skill": 1, + "recruit_priority": 80, + "promote_priority": 0 } ], "Support": [ { "name": "灵知", "skill": 3, - "alternate_skill": 1 + "alternate_skill": 1, + "recruit_priority": 10, + "promote_priority": 500 }, { "name": "令", "skill": 3, - "alternate_skill": 1 + "alternate_skill": 1, + "recruit_priority": 10, + "promote_priority": 900 }, { "name": "铃兰", "skill": 3, - "alternate_skill": 2 + "alternate_skill": 2, + "recruit_priority": 10, + "promote_priority": 300 }, { "name": "安洁莉娜", "skill": 3, - "alternate_skill": 2 + "alternate_skill": 2, + "recruit_priority": 10, + "promote_priority": 200 }, { "name": "浊心斯卡蒂", - "skill": 2 + "skill": 2, + "recruit_priority": 10, + "promote_priority": 500 }, { "name": "梓兰", - "skill": 1 + "skill": 1, + "recruit_priority": 10, + "promote_priority": 0 } ], "Alternate": [ { "name": "预备干员-近战", - "skill": 0 + "skill": 0, + "recruit_priority": 5, + "promote_priority": 0, + "is_alternate": true }, { "name": "预备干员-狙击", - "skill": 0 + "skill": 0, + "recruit_priority": 5, + "promote_priority": 0, + "is_alternate": true }, { "name": "预备干员-术师", - "skill": 0 + "skill": 0, + "recruit_priority": 5, + "promote_priority": 0, + "is_alternate": true }, { "name": "预备干员-后勤", - "skill": 0 + "skill": 0, + "recruit_priority": 5, + "promote_priority": 0, + "is_alternate": true } ] } diff --git a/src/MeoAssistant/RoguelikeRecruitConfiger.cpp b/src/MeoAssistant/RoguelikeRecruitConfiger.cpp index cddfa66b1e..374c59ebd6 100644 --- a/src/MeoAssistant/RoguelikeRecruitConfiger.cpp +++ b/src/MeoAssistant/RoguelikeRecruitConfiger.cpp @@ -29,6 +29,9 @@ bool asst::RoguelikeRecruitConfiger::parse(const json::value& json) std::string name = oper_info.at("name").as_string(); RoguelikeOperInfo info; info.name = name; + info.recruit_priority = oper_info.get("recruit_priority", 0); + info.promote_priority = oper_info.get("promote_priority", 0); + info.is_alternate = oper_info.get("is_alternate", false); info.skill = oper_info.at("skill").as_integer(); info.alternate_skill = oper_info.get("alternate_skill", 0); info.skill_usage = static_cast(oper_info.get("skill_usage", 1)); diff --git a/src/MeoAssistant/RoguelikeRecruitConfiger.h b/src/MeoAssistant/RoguelikeRecruitConfiger.h index aea8cdc3b1..c59e392ea8 100644 --- a/src/MeoAssistant/RoguelikeRecruitConfiger.h +++ b/src/MeoAssistant/RoguelikeRecruitConfiger.h @@ -15,6 +15,9 @@ namespace asst struct RoguelikeOperInfo { std::string name; + int recruit_priority = 0; // 招募优先级 (0-1000) + int promote_priority = 0; // 晋升优先级 (0-1000) + bool is_alternate = false; // 是否后备干员 (允许重复招募、划到后备干员时不再往右划动) int skill = 0; int alternate_skill = 0; BattleSkillUsage skill_usage = BattleSkillUsage::Possibly; diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index cda7b61276..f51d9b287f 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -38,76 +38,222 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() recruited = true; }; + const auto& recruit_cfg = Resrc.roguelike_recruit(); + + // 编队信息 (已有角色) + std::string str_chars_info = m_status->get_str(RuntimeStatus::RoguelikeCharOverview).value_or(json::value().to_string()); + json::value json_chars_info = json::parse(str_chars_info).value_or(json::value()); + const auto& chars_map = json_chars_info.as_object(); + + // 候选干员 + std::vector recruit_list; + constexpr int SwipeTimes = 5; int i = 0; + + // 翻页找出所有候选干员 for (; i != SwipeTimes; ++i) { auto image = m_ctrler->get_image(); RoguelikeRecruitImageAnalyzer analyzer(image); if (!analyzer.analyze()) { - return false; - } - - const auto& oper_list = analyzer.get_result(); - for (const auto& info : oper_list) { - // 先看看有没有精二的 - if (info.elite != 2) { - continue; - } - recruit_oper(info); - break; - } - - if (!recruited) { - for (const auto& info : oper_list) { - if (!info.required) { - continue; - } - // 拿个精一 50 以上的 - if (info.elite == 0 || - (info.elite == 1 && info.level < 50)) { - continue; - } - recruit_oper(info); - break; - } - } - - if (!recruited) { - Log.info("All are lower"); - // 随便招个精一的 - for (const auto& info : oper_list) { - if (!info.required) { - continue; - } - if (info.elite == 0) { - continue; - } - recruit_oper(info); - break; - } - } - - // 这玩意选了也没啥用,不如省点理智 - //if (!recruited) { - // // 随便招个 - // Log.info("All are very lower"); - // auto info = oper_list.front(); - // recruit_oper(info); - //} - - // 没有合适的干员,尝试向右翻页 - if (!recruited) { - ProcessTask(*this, { "SlowlySwipeToTheRight" }).run(); + // 本页没有检测到符合条件的干员,向右滑动 + slowly_swipe(ProcessTaskAction::SlowlySwipeToTheRight); sleep(Task.get("Roguelike1Custom-HijackSquad")->rear_delay); continue; } - // 已经招募到合适的干员 - return true; + const auto& oper_list = analyzer.get_result(); + bool stop_swipe = false; + + for (const auto& oper_info : oper_list) { + // 查询招募配置 + auto& recruit_info = recruit_cfg.get_oper_info(oper_info.name); + if (recruit_info.name.empty()) { + continue; + } + + int priority = 0; + + // 查询编队是否已持有该干员 + const auto& char_opt = chars_map.find(oper_info.name); + + if (char_opt.has_value()) { + // 干员已在编队中 + int elite = char_opt.value().get("elite", 0); + if (elite == 2) { + // 干员已精二,忽略 + continue; + } + + if (recruit_info.is_alternate) { + // 预备干员可以重复招募 + priority = recruit_info.recruit_priority; + } + else { + // 干员待晋升 + priority = recruit_info.promote_priority; + } + } + else { + // 干员待招募 + if (oper_info.elite == 2) { + // TODO: 招募时已精二 (随机提升或对应分队) => promoted_priority + priority = recruit_info.recruit_priority; + } + else { + // 招募时未精二 + priority = recruit_info.recruit_priority; + } + } + + // 已经划到后备干员,且已有候选干员,假定后面的干员优先级不会更高,不再划动 + if (recruit_info.is_alternate && !recruit_list.empty()) { + stop_swipe = true; + } + + // 添加到候选名单 + auto existing_it = std::ranges::find_if(recruit_list, [&](const RoguelikeRecruitInfo& pri) -> bool { + return pri.name == recruit_info.name; + }); + if (existing_it == recruit_list.cend()) { + RoguelikeRecruitInfo info; + info.name = recruit_info.name; + info.priority = priority; + info.is_alternate = recruit_info.is_alternate; + info.page_index = i; + recruit_list.emplace_back(info); + } + } + + if (stop_swipe) { + break; + } + + // 向右滑动 + slowly_swipe(ProcessTaskAction::SlowlySwipeToTheRight); + sleep(Task.get("Roguelike1Custom-HijackSquad")->rear_delay); } - Log.info(__FUNCTION__, "did not choose oper."); - swipe_to_the_left_of_operlist(i / 2 + 1); + // 没有候选干员,进入后备逻辑 + if (recruit_list.empty()) { + Log.trace(__FUNCTION__, "| No oper in recruit list."); + + // 如果划动过,先划回最左边 + if (i != 0) { + swipe_to_the_left_of_operlist(i / 2 + 1); + } + + auto image = m_ctrler->get_image(); + RoguelikeRecruitImageAnalyzer analyzer(image); + if (!analyzer.analyze()) { + Log.error(__FUNCTION__, "| Random recruitment analyse failed"); + return false; + } + + const auto& oper_list = analyzer.get_result(); + + // 可能是晋升界面,随便选个精二的 + for (const auto& info : oper_list) { + if (!info.required) { + continue; + } + if (info.elite != 2) { + continue; + } + Log.trace(__FUNCTION__, "| Choose random elite 2:", info.name, info.elite, info.level); + recruit_oper(info); + return true; + } + + // 仍然没选,随便选个精一 50 以上的 + for (const auto& info : oper_list) { + if (!info.required) { + continue; + } + if (info.elite == 0 || + (info.elite == 1 && info.level < 50)) { + continue; + } + Log.trace(__FUNCTION__, "| Choose random elite 1:", info.name, info.elite, info.level); + recruit_oper(info); + return true; + } + + Log.trace(__FUNCTION__, "| Did not choose oper"); + return false; + } + + // 选择优先级最高的干员 + auto selected_oper = std::ranges::max_element(recruit_list, [&](asst::RoguelikeRecruitInfo& lhs, asst::RoguelikeRecruitInfo& rhs) -> int { + return rhs.priority > lhs.priority; + }); + if (selected_oper == recruit_list.cend()) { + Log.trace(__FUNCTION__, "| No opers in recruit list."); + return false; + } + + auto& char_name = selected_oper->name; + Log.trace(__FUNCTION__, "| Top priority oper:", char_name, selected_oper->priority, "page", selected_oper->page_index, "/", i); + + bool is_rtl = false; + + // 如果划动过,判断目标角色离哪个方向更近 + if (i != 0) { + // 页码大于一半: 从右往左划动 + // 页码小于一半: 划回最左边再往右 + is_rtl = (selected_oper->page_index * 2) >= i; + if (!is_rtl) { + swipe_to_the_left_of_operlist(i / 2 + 1); + } + } + + return check_char(char_name, is_rtl); +} + +bool asst::RoguelikeRecruitTaskPlugin::check_char(const std::string& char_name, bool is_rtl) +{ + LogTraceFunction; + + constexpr int SwipeTimes = 10; + int i = 0; + for (; i != SwipeTimes; ++i) { + auto image = m_ctrler->get_image(); + RoguelikeRecruitImageAnalyzer analyzer(image); + + // 只处理识别成功的情况,失败(无任何结果)时继续滑动 + if (analyzer.analyze()) { + const auto& chars = analyzer.get_result(); + auto it = ranges::find_if(chars, + [&](const BattleRecruitOperInfo& oper) -> bool { + return oper.name == char_name; + }); + + std::string oper_names = ""; + for (const auto& oper : chars) { + if (!oper_names.empty()) { + oper_names += ", "; + } + oper_names += oper.name; + } + Log.info(__FUNCTION__, "| Oper list:", oper_names); + + if (it != chars.cend()) { + select_oper(*it); + return true; + } + } + + // 没识别到目标干员,可能不在这一页,继续划动 + if (is_rtl) { + slowly_swipe(ProcessTaskAction::SlowlySwipeToTheLeft); + } + else { + slowly_swipe(ProcessTaskAction::SlowlySwipeToTheRight); + } + sleep(Task.get("Roguelike1Custom-HijackSquad")->rear_delay); + } + Log.info(__FUNCTION__, "| Cannot find oper `" + char_name + "`"); + swipe_to_the_left_of_operlist(); return false; } @@ -120,40 +266,7 @@ bool asst::RoguelikeRecruitTaskPlugin::check_core_char() return false; } m_status->set_str("RoguelikeCoreChar", ""); - constexpr int SwipeTimes = 10; - int i = 0; - for (; i != SwipeTimes; ++i) { - auto image = m_ctrler->get_image(); - RoguelikeRecruitImageAnalyzer analyzer(image); - if (!analyzer.analyze()) { - Log.info(__FUNCTION__, "| Unable to analyze image."); - break; - } - const auto& chars = analyzer.get_result(); - auto it = ranges::find_if(chars, - [&](const BattleRecruitOperInfo& oper) -> bool { - return oper.name == core_opt.value(); - }); - - std::string oper_names = ""; - for (const auto& oper : chars) { - if (!oper_names.empty()) { - oper_names += ", "; - } - oper_names += oper.name; - } - Log.info(__FUNCTION__, "| Oper list:", oper_names); - if (it == chars.cend()) { - slowly_swipe(ProcessTaskAction::SlowlySwipeToTheRight); - sleep(Task.get("Roguelike1Custom-HijackSquad")->rear_delay); - continue; - } - select_oper(*it); - return true; - } - Log.info(__FUNCTION__, "| Cannot find oper `" + core_opt.value() + "`"); - swipe_to_the_left_of_operlist(); - return false; + return check_char(core_opt.value()); } void asst::RoguelikeRecruitTaskPlugin::select_oper(const BattleRecruitOperInfo& oper) @@ -177,8 +290,8 @@ void asst::RoguelikeRecruitTaskPlugin::select_oper(const BattleRecruitOperInfo& void asst::RoguelikeRecruitTaskPlugin::swipe_to_the_left_of_operlist(int loop_times) { LogTraceFunction; - static Rect begin_rect = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->specific_rect; - static Rect end_rect = Task.get("RoguelikeRecruitSwipeToTheLeftEnd")->specific_rect; + static Rect begin_rect = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->specific_rect; // 1080, 200, 100, 300 + static Rect end_rect = Task.get("RoguelikeRecruitSwipeToTheLeftEnd")->specific_rect; // 400, 200, 100, 300 static int duration = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->pre_delay; static int extra_delay = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->rear_delay; static int cfg_loop_times = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->max_times; @@ -195,8 +308,8 @@ void asst::RoguelikeRecruitTaskPlugin::swipe_to_the_left_of_operlist(int loop_ti void asst::RoguelikeRecruitTaskPlugin::slowly_swipe(ProcessTaskAction action) { LogTraceFunction; - static Rect right_rect = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->specific_rect; - static Rect left_rect = Task.get("RoguelikeRecruitSlowlySwipeLeftRect")->specific_rect; + static Rect right_rect = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->specific_rect; // 780, 200, 100, 300 + static Rect left_rect = Task.get("RoguelikeRecruitSlowlySwipeLeftRect")->specific_rect; // 360, 200, 100, 300 static int duration = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->pre_delay; static int extra_delay = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->rear_delay; diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h index 9174671425..eb8e83e56e 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h @@ -5,6 +5,14 @@ namespace asst { + // 干员招募信息 + struct RoguelikeRecruitInfo + { + std::string name; // 干员名字 + int priority = 0; // 招募优先级 (0-1000) + int page_index = 0; // 所在页码 (用于判断翻页方向) + bool is_alternate = false; // 是否后备干员 (允许重复招募、划到后备干员时不再往右划动) + }; class RoguelikeRecruitTaskPlugin : public AbstractTaskPlugin { public: @@ -20,6 +28,7 @@ namespace asst private: bool check_core_char(); + bool check_char(const std::string& char_name, bool is_rtl = false); void select_oper(const BattleRecruitOperInfo& oper); }; } From c6c018fd8ea59c08b167d3b9ee9b5dde50241aab Mon Sep 17 00:00:00 2001 From: et Date: Mon, 15 Aug 2022 21:50:56 +0800 Subject: [PATCH 3/7] =?UTF-8?q?style:=20=E4=B8=BA=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=9A=84=E5=87=BD=E6=95=B0=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp | 6 ++++-- src/MeoAssistant/RoguelikeRecruitTaskPlugin.h | 12 ++++++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index f51d9b287f..da5ce9e2ac 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -195,14 +195,16 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() auto& char_name = selected_oper->name; Log.trace(__FUNCTION__, "| Top priority oper:", char_name, selected_oper->priority, "page", selected_oper->page_index, "/", i); + // 滑动方向 + // 页码大于一半: 从右往左划动 + // 页码小于一半: 划回最左边再往右 bool is_rtl = false; // 如果划动过,判断目标角色离哪个方向更近 if (i != 0) { - // 页码大于一半: 从右往左划动 - // 页码小于一半: 划回最左边再往右 is_rtl = (selected_oper->page_index * 2) >= i; if (!is_rtl) { + // 从左往右需要先划回最左边 swipe_to_the_left_of_operlist(i / 2 + 1); } } diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h index eb8e83e56e..879477053f 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.h @@ -23,11 +23,19 @@ namespace asst protected: virtual bool _run() override; - void swipe_to_the_left_of_operlist(int loop_times = 1); // 滑动到干员列表的最左侧 - void slowly_swipe(ProcessTaskAction action); // 缓慢向干员列表的左侧/右侧滑动 + // 滑动到干员列表的最左侧 + void swipe_to_the_left_of_operlist(int loop_times = 1); + // 缓慢向干员列表的左侧/右侧滑动 + void slowly_swipe(ProcessTaskAction action); private: bool check_core_char(); + // 招募指定干员 + // + // 输入参数: + // char_name: 干员名称 + // is_rtl: 滑动方向 (true: 从右向左; false: 从左向右,需要先滑动到最左侧) + // 返回值: 招募结果 (true: 成功; false: 失败) bool check_char(const std::string& char_name, bool is_rtl = false); void select_oper(const BattleRecruitOperInfo& oper); }; From 11b3e695ffc78bb8a7c60bf5506d888c5d65ada0 Mon Sep 17 00:00:00 2001 From: et Date: Mon, 15 Aug 2022 21:51:30 +0800 Subject: [PATCH 4/7] =?UTF-8?q?perf:=20=E4=BD=BF=E7=94=A8=E9=87=8D?= =?UTF-8?q?=E5=86=99=E7=9A=84=20ranges?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index da5ce9e2ac..cd500c6da8 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -112,7 +112,7 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() } // 添加到候选名单 - auto existing_it = std::ranges::find_if(recruit_list, [&](const RoguelikeRecruitInfo& pri) -> bool { + auto existing_it = ranges::find_if(recruit_list, [&](const RoguelikeRecruitInfo& pri) -> bool { return pri.name == recruit_info.name; }); if (existing_it == recruit_list.cend()) { @@ -184,7 +184,7 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() } // 选择优先级最高的干员 - auto selected_oper = std::ranges::max_element(recruit_list, [&](asst::RoguelikeRecruitInfo& lhs, asst::RoguelikeRecruitInfo& rhs) -> int { + auto selected_oper = ranges::max_element(recruit_list, [&](asst::RoguelikeRecruitInfo& lhs, asst::RoguelikeRecruitInfo& rhs) -> int { return rhs.priority > lhs.priority; }); if (selected_oper == recruit_list.cend()) { From 423c6463b24fcdcff1535a33ccc43ac735777b56 Mon Sep 17 00:00:00 2001 From: et Date: Mon, 15 Aug 2022 21:52:27 +0800 Subject: [PATCH 5/7] =?UTF-8?q?style:=20=E4=B8=BA=20lambda=20=E5=8A=A0?= =?UTF-8?q?=E4=B8=8A=20const?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index cd500c6da8..c31464413b 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -184,7 +184,7 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() } // 选择优先级最高的干员 - auto selected_oper = ranges::max_element(recruit_list, [&](asst::RoguelikeRecruitInfo& lhs, asst::RoguelikeRecruitInfo& rhs) -> int { + auto selected_oper = ranges::max_element(recruit_list, [&](const asst::RoguelikeRecruitInfo& lhs, const asst::RoguelikeRecruitInfo& rhs) -> int { return rhs.priority > lhs.priority; }); if (selected_oper == recruit_list.cend()) { From 2a9318bb1d981294dd9f696a550b71011ecba006 Mon Sep 17 00:00:00 2001 From: et Date: Mon, 15 Aug 2022 21:53:35 +0800 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20=E5=90=8E=E5=A4=87=E6=8B=9B=E5=8B=9F?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E6=97=A0=E8=A7=86=20required=20=E6=A0=87?= =?UTF-8?q?=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index c31464413b..b83c1c0951 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -154,9 +154,6 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() // 可能是晋升界面,随便选个精二的 for (const auto& info : oper_list) { - if (!info.required) { - continue; - } if (info.elite != 2) { continue; } @@ -167,9 +164,6 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() // 仍然没选,随便选个精一 50 以上的 for (const auto& info : oper_list) { - if (!info.required) { - continue; - } if (info.elite == 0 || (info.elite == 1 && info.level < 50)) { continue; From a7d374b5135b9ccf377a73ef68462484e7e8d9b6 Mon Sep 17 00:00:00 2001 From: et Date: Mon, 15 Aug 2022 21:58:44 +0800 Subject: [PATCH 7/7] =?UTF-8?q?perf:=20=E7=B2=BE=E7=AE=80=E6=9C=80?= =?UTF-8?q?=E9=AB=98=E4=BC=98=E5=85=88=E7=BA=A7=E6=8E=92=E5=BA=8F=E7=AE=97?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index b83c1c0951..83dc9249ee 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -178,9 +178,7 @@ bool asst::RoguelikeRecruitTaskPlugin::_run() } // 选择优先级最高的干员 - auto selected_oper = ranges::max_element(recruit_list, [&](const asst::RoguelikeRecruitInfo& lhs, const asst::RoguelikeRecruitInfo& rhs) -> int { - return rhs.priority > lhs.priority; - }); + auto selected_oper = ranges::max_element(recruit_list, std::less{}, std::mem_fn(&RoguelikeRecruitInfo::priority)); if (selected_oper == recruit_list.cend()) { Log.trace(__FUNCTION__, "| No opers in recruit list."); return false;