diff --git a/resource/battle/GA-EX8-raid.json b/resource/battle/GA-EX8-raid.json new file mode 100644 index 0000000000..e9fe8d1fb4 --- /dev/null +++ b/resource/battle/GA-EX8-raid.json @@ -0,0 +1,131 @@ +{ + "minimum_required": "v4.0", + "desc": { + "title": "《AI 都比我打得好》", + "details": "https://www.bilibili.com/video/BV1zS4y1U76j", + "requirements": "" + }, + "stage_name": "千层蛋糕", + "opers": [ + { + "name": "银灰" + }, + { + "name": "凯尔希" + }, + { + "name": "史尔特尔" + }, + { + "name": "泥岩" + } + ], + "actions": [ + { + "type": "二倍速" + }, + { + "name": "泥岩", + "location": [ + 2, + 6 + ], + "direction": "右" + }, + { + "name": "银灰", + "location": [ + 4, + 3 + ], + "direction": "左" + }, + { + "kills": 6, + "pre_delay": 2000, + "type": "技能", + "name": "银灰" + }, + { + "pre_delay": 12000, + "name": "史尔特尔", + "location": [ + 4, + 2 + ], + "direction": "下" + }, + { + "pre_delay": 1000, + "type": "技能", + "name": "史尔特尔" + }, + { + "kills": 19, + "name": "凯尔希", + "location": [ + 5, + 2 + ], + "direction": "右" + }, + { + "name": "Mon3tr", + "location": [ + 8, + 2 + ], + "direction": "上" + }, + { + "kills": 23, + "pre_delay": 1000, + "type": "技能", + "name": "凯尔希" + }, + { + "name": "银灰", + "location": [ + 8, + 5 + ], + "direction": "上" + }, + { + "kills": 26, + "type": "技能", + "name": "银灰", + "rear_delay": 6000 + }, + { + "name": "史尔特尔", + "location": [ + 8, + 6 + ], + "direction": "上" + }, + { + "pre_delay": 1000, + "type": "技能", + "name": "史尔特尔" + }, + { + "kills": 28, + "type": "撤退", + "name": "史尔特尔" + }, + { + "name": "Mon3tr", + "type": "撤退" + }, + { + "name": "Mon3tr", + "location": [ + 5, + 1 + ], + "direction": "右" + } + ] +} diff --git a/resource/tasks.json b/resource/tasks.json index 409a4aeba4..9a08b67c24 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -959,7 +959,7 @@ "RecruitSkipWithoutButton" ] }, - "RecruitFinishLoading":{ + "RecruitFinishLoading": { "algorithm": "OcrDetect", "action": "doNothing", "text": [ @@ -1753,7 +1753,7 @@ "Stop" ] }, - "RecruitCheckTimeUnreduced":{ + "RecruitCheckTimeUnreduced": { "action": "Stop", "template": "RecruitTimeReduce.png", "Doc": "检查时间是不是没有调整过", @@ -1777,7 +1777,7 @@ "RecruitFlag" ] }, - "RecruitConfirmLoading":{ + "RecruitConfirmLoading": { "algorithm": "OcrDetect", "action": "doNothing", "text": [ @@ -3432,7 +3432,7 @@ }, "BattleAvatarData": { "template": "empty.png", - "templThreshold": 0.8 + "templThreshold": 0.6 }, "BattleKillsFlag": { "roi": [ @@ -3525,13 +3525,13 @@ }, "BattleOperAvailable": { "template": "empty.png", - "specialThreshold": 110, + "specialThreshold": 100, "specialThreshold_Doc": "用于做V通道平均值阈值", "rectMove": [ - -41, - 6, - 31, - 25 + 0, + 0, + 10, + 10 ] }, "BattleOperRoleRange": { diff --git a/src/MeoAssistant/BattleImageAnalyzer.cpp b/src/MeoAssistant/BattleImageAnalyzer.cpp index bbf73c586f..f247901f78 100644 --- a/src/MeoAssistant/BattleImageAnalyzer.cpp +++ b/src/MeoAssistant/BattleImageAnalyzer.cpp @@ -387,15 +387,22 @@ bool asst::BattleImageAnalyzer::kills_analyze() } kills_analyzer.sort_result_by_score(); - // 这里的结果应该是 "击杀数/总的敌人数",例如 "0/41" - std::string kills_res = kills_analyzer.get_result().front().text; - size_t pos = kills_res.find('/'); + std::string kills_text; + size_t pos = std::string::npos; + for (auto& res : kills_analyzer.get_result()) { + // 这里的结果应该是 "击杀数/总的敌人数",例如 "0/41" + pos = res.text.find('/'); + if (pos != std::string::npos) { + kills_text = res.text; + break; + } + } if (pos == std::string::npos) { return false; } // 例子中的"0" - std::string kills_count = kills_res.substr(0, pos); + std::string kills_count = kills_text.substr(0, pos); if (kills_count.empty() || !std::all_of(kills_count.cbegin(), kills_count.cend(), [](char c) -> bool {return std::isdigit(c);})) { @@ -403,6 +410,7 @@ bool asst::BattleImageAnalyzer::kills_analyze() } int cur_kills = std::stoi(kills_count); m_kills = std::max(m_kills, cur_kills); + Log.trace("Kills:", m_kills, cur_kills); return true; } diff --git a/src/MeoAssistant/BattleProcessTask.cpp b/src/MeoAssistant/BattleProcessTask.cpp index a1d0a03cef..013b294ede 100644 --- a/src/MeoAssistant/BattleProcessTask.cpp +++ b/src/MeoAssistant/BattleProcessTask.cpp @@ -39,8 +39,16 @@ bool asst::BattleProcessTask::get_stage_info() { const auto& tile = Resrc.tile(); - m_side_tile_info = tile.calc(m_stage_name, true); m_normal_tile_info = tile.calc(m_stage_name, false); + m_side_tile_info = tile.calc(m_stage_name, true); + +#ifdef ASST_DEBUG + auto draw = m_ctrler->get_image(); + for (const auto& [loc, info] : m_normal_tile_info) { + std::string text = "( " + std::to_string(loc.x) + ", " + std::to_string(loc.y) + " )"; + cv::putText(draw, text, cv::Point(info.pos.x, info.pos.y), 1, 1, cv::Scalar(0, 0, 255)); + } +#endif if (m_side_tile_info.empty() || m_normal_tile_info.empty()) { return false; @@ -122,7 +130,7 @@ bool asst::BattleProcessTask::update_opers_info() int right_index = 0; // 干员数变多了,之前的干员可能位于 [当前位置 - |size_change|, 当前位置 ] 之间 if (is_increased) { - left_index = static_cast(cur_oper.index) - size_change; + left_index = std::max(0, static_cast(cur_oper.index) - size_change); right_index = static_cast(cur_oper.index); } // 干员数减少了,之前的干员可能位于 [当前位置 , 当前位置 + |size_change|] 之间 @@ -140,37 +148,65 @@ bool asst::BattleProcessTask::update_opers_info() } } - decltype(ranged_iters)::value_type matched_iter = ranged_iters.front(); - - if (ranged_iters.empty()) { - Log.error("ranged_iters empty", left_index, right_index); - return false; + std::string oper_name = "Unknown"; + if (is_increased && !cur_oper.available) { + continue; } - else if (ranged_iters.size() > 1) { - MatchImageAnalyzer avatar_analyzer(cur_oper.avatar); - avatar_analyzer.set_task_info("BattleAvatarData"); - MatchRect matched_result; - // 遍历比较,得分最高的那个就说明是对应的那个 - for (const auto& iter : ranged_iters) { - avatar_analyzer.set_templ(iter->second.avatar); - if (!avatar_analyzer.analyze()) { - continue; - } - if (matched_result.score < avatar_analyzer.get_result().score) { - matched_result = avatar_analyzer.get_result(); - matched_iter = iter; + // 新多出来的干员,上一帧画面里应该是没有的,把所有不在场的都拿出来比较下 + if (ranged_iters.empty()) { + for (auto iter = pre_opers_info.cbegin(); iter != pre_opers_info.cend(); ++iter) { + if (iter->second.index == SIZE_MAX) { + ranged_iters.emplace_back(iter); } } } + + MatchImageAnalyzer avatar_analyzer(cur_oper.avatar); + avatar_analyzer.set_task_info("BattleAvatarData"); + MatchRect matched_result; + decltype(ranged_iters)::value_type matched_iter; + + // 遍历比较,得分最高的那个就说明是对应的那个 + for (const auto& iter : ranged_iters) { + avatar_analyzer.set_templ(iter->second.avatar); + if (!avatar_analyzer.analyze()) { + continue; + } + if (matched_result.score < avatar_analyzer.get_result().score) { + matched_result = avatar_analyzer.get_result(); + matched_iter = iter; + } + } + // 一个都没匹配上,考虑是新增的召唤物,或者别的东西,点开来看一下 + if (matched_result.score == 0) { + battle_pause(); + m_ctrler->click(cur_oper.rect); + sleep(Task.get("BattleUseOper")->pre_delay); + + auto image = m_ctrler->get_image(); + OcrImageAnalyzer name_analyzer(image); + name_analyzer.set_task_info("BattleOperName"); + name_analyzer.set_replace( + std::dynamic_pointer_cast( + Task.get("Roguelike1RecruitData")) + ->replace_map); + + if (name_analyzer.analyze()) { + name_analyzer.sort_result_by_score(); + oper_name = name_analyzer.get_result().front().text; + } + battle_pause(); + cancel_selection(); + } else { - ; // 只有一个干员的时候就不用计算,就是唯一的那个 + oper_name = matched_iter->first; } auto temp_oper = cur_oper; - temp_oper.name = matched_iter->first; + temp_oper.name = oper_name; // 保存当前干员信息 - m_opers_info.emplace(matched_iter->first, std::move(temp_oper)); + m_opers_info.emplace(oper_name, std::move(temp_oper)); } return true; } @@ -180,25 +216,28 @@ bool asst::BattleProcessTask::do_action(const BattleAction& action) if (!wait_condition(action)) { return false; } + sleep(action.pre_delay); + bool ret = false; switch (action.type) { case BattleActionType::Deploy: - return oper_deploy(action); + ret = oper_deploy(action); break; case BattleActionType::Retreat: - return oper_retreat(action); + ret = oper_retreat(action); break; case BattleActionType::UseSkill: - return use_skill(action); + ret = use_skill(action); break; case BattleActionType::SwitchSpeed: - return battle_speedup(); + ret = battle_speedup(); break; case BattleActionType::BulletTime: break; } + sleep(action.rear_delay); - return false; + return ret; } bool asst::BattleProcessTask::wait_condition(const BattleAction& action) @@ -231,10 +270,9 @@ bool asst::BattleProcessTask::oper_deploy(const BattleAction& action) // TODO,临时调试方案。正式版本这里需要对 group_name -> oper_name 做一个转换 iter = m_opers_info.find(action.group_name); if (iter == m_opers_info.cend()) { - Log.error("battle opers group", action.group_name, "not found"); - return false; + Log.info("battle opers group", action.group_name, "not found"); } - } while (!iter->second.available); + } while (iter == m_opers_info.cend() || !iter->second.available); // 点击干员 Rect oper_rect = iter->second.rect; @@ -243,7 +281,6 @@ bool asst::BattleProcessTask::oper_deploy(const BattleAction& action) // 拖动到场上 Point placed_point = m_side_tile_info[action.location].pos; - m_used_opers_loc[iter->first] = action.location; Rect placed_rect{ placed_point.x ,placed_point.y, 1, 1 }; m_ctrler->swipe(oper_rect, placed_rect, swipe_oper_task_ptr->pre_delay); @@ -276,6 +313,12 @@ bool asst::BattleProcessTask::oper_deploy(const BattleAction& action) m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->rear_delay); } + + m_used_opers_loc[iter->first] = action.location; + + iter->second.index = SIZE_MAX; + //m_opers_info.erase(iter); + //sleep(use_oper_task_ptr->pre_delay); return true; diff --git a/src/MeoAssistant/DebugTask.cpp b/src/MeoAssistant/DebugTask.cpp index 1b4d31536f..8a74e639d5 100644 --- a/src/MeoAssistant/DebugTask.cpp +++ b/src/MeoAssistant/DebugTask.cpp @@ -9,6 +9,6 @@ asst::DebugTask::DebugTask(AsstCallback callback, void* callback_arg) { //auto task_ptr = std::make_shared(callback, callback_arg, TaskType); auto task_ptr = std::make_shared(callback, callback_arg, TaskType); - task_ptr->set_stage_name("切尔诺伯格"); + task_ptr->set_stage_name("千层蛋糕"); m_subtasks.emplace_back(task_ptr); } diff --git a/src/MeoAssistant/Resource.cpp b/src/MeoAssistant/Resource.cpp index 0ded74d019..e31f954b0c 100644 --- a/src/MeoAssistant/Resource.cpp +++ b/src/MeoAssistant/Resource.cpp @@ -72,7 +72,7 @@ bool asst::Resource::load(const std::string& dir) continue; } if (!m_battle_cfg_unique_ins.load(entry.path().u8string())) { - m_last_error = entry.path().u8string() + " Load field"; + m_last_error = entry.path().u8string() + " Load faild"; return false; } } diff --git a/src/MeoAssistant/TilePack.cpp b/src/MeoAssistant/TilePack.cpp index 04811081bd..aeb67e0ee2 100644 --- a/src/MeoAssistant/TilePack.cpp +++ b/src/MeoAssistant/TilePack.cpp @@ -72,11 +72,13 @@ std::unordered_map asst::TilePack::calc( Log.error("Unknown tile type:", tile.tileKey); } - dst.emplace(Point(static_cast(x), static_cast(y)), TileInfo{ + Point loc(static_cast(x), static_cast(y)); + dst.emplace(loc, TileInfo{ static_cast(tile.buildableType), static_cast(tile.heightType), key, - Point(static_cast(cv_p.x), static_cast(cv_p.y)) }); + Point(static_cast(cv_p.x), static_cast(cv_p.y)), + loc }); } } return dst;