diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f89008ff9..aa0fe6ab2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v4.10.0-beta.2 + +- 修复 `引航者试炼` 部分已知问题 @MistEO +- 更新 `保全派驻` 协议,新增部分功能支持 @MistEO +- 开放 掉落识别上传企鹅物流 @MistEO + ## v4.10.0-beta.1 - 修复 `引航者试炼` 地图格子错误 @horror-proton diff --git a/docs/3.7-保全派驻协议.md b/docs/3.7-保全派驻协议.md index 3a68c26618..e772afd08d 100644 --- a/docs/3.7-保全派驻协议.md +++ b/docs/3.7-保全派驻协议.md @@ -28,18 +28,19 @@ ], "tool_men": { // 剩余所需各职业人数,按费用排序随便拿,可选 "Pioneer": 13, - "Warrior": 2, // 中英文均可 + "近卫": 2, // 中英文均可 "Medic": 2 }, - "drop_buffs": [ // 战斗后拿buff的优先级。好像只有第四层有?可选 - "定向部署支援系统" - ], - "drop_tool_men": [ // 战斗结束后招募干员职业的优先级,可选 + "drops": [ // 战斗开始时和战斗中途,招募干员、获取装备优先级 "空弦", - "能天使", - "先锋", // 中英文均可 + "能天使", // 支持干员名、职业名 + "先锋", // 职业名中英文均可 "Support", - "无需增调干员" // 不招人 + "无需增调干员", // 不招人 + "重整导能组件", // 支持装备名,全写一起.jpg + "反制导能组件", + "战备激活阀", // 关卡中途的可选装备,也也放这里。需要配合 actions 中 type: GetDrops 使用 + "改派发讯器", ], "stages": [ { @@ -88,7 +89,6 @@ } ], "draw_as_possible": true, // “调配干员”按钮,是否好了就用,可选,默认 true - "actions": [ // 可选 // 基本复用抄作业的逻辑,可参考 3.3-战斗流程协议.md // 符合 action 的条件就执行 action,否则执行上面的 strategies 的逻辑 @@ -100,10 +100,16 @@ "name": "棘刺" }, { - "type": "CheckIfStartOver", // 检查干员在不在,不在就退出重开 - "tool_men": { - "Pioneer": 2 - } + "type": "CheckIfStartOver", // 新 type,检查战利品并获取 + "name": "棘刺" + }, + { + "type": "GetDrops", // 检查获取战斗中途的战利品,将按照 drops 字段的排序进行拿去 + // 若 drops 字段为空,或 drops 中的物品一个都没识别到,将会选择放弃战利品 + // 若执行动作时未识别到战利品获取,将会直接跳过该 action + "kills": 20, + "pre_delay": 3000 // 小技巧:一般来说都是打死了某个怪才会出,所以可以基于击杀数来触发 + // 但是从击杀数达到到选择界面跳出来可能有个延迟,所以建议价格 pre_delay }, { "name": "桃金娘", diff --git a/resource/copilot/SSS_Test.json b/resource/copilot/SSS_Test.json index 61b0ff0806..ad5ae3d173 100644 --- a/resource/copilot/SSS_Test.json +++ b/resource/copilot/SSS_Test.json @@ -33,15 +33,16 @@ "近卫": 6, "医疗": 2 }, - "drop_buffs": [ - "定向部署支援系统" - ], - "drop_tool_men": [ + "drops": [ "空弦", "能天使", "先锋", - "辅助", - "无需增调干员" + "Support", + "无需增调干员", + "重整导能组件", + "反制导能组件", + "战备激活阀", + "改派发讯器" ], "stages": [ { diff --git a/resource/tasks.json b/resource/tasks.json index bcc867dd70..f94ae8cc59 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -6154,12 +6154,14 @@ "specialParams": [ 400, 2, - 0 + 0, + 100 ], "specialParamsDoc": [ "设置朝向时的滑动距离", "滑动初速度(平均速度是固定的,初速度快末速度慢相当于一直减速)", - "滑动末速度" + "滑动末速度", + "最小滑动时长" ] }, "BattleOpersFlag": { @@ -9437,14 +9439,19 @@ ] }, "SSSDropRecruitmentFlag": { + "algorithm": "OcrDetect", "action": "DoNothing", - "roi": [ - 0, - 39, - 250, - 203 + "text": [ + "请选择", + "请进行" ], - "postDelay": 2000, + "roi": [ + 163, + 78, + 900, + 112 + ], + "postDelay": 5000, "next": [ "SSSStartFighting2", "SSSDropRecruitmentFlag" @@ -9470,9 +9477,9 @@ "cache": false, "roi": [ 0, - 434, + 352, 1280, - 169 + 263 ] }, "SSSDropRecruitmentConfrim": { @@ -9480,13 +9487,64 @@ "action": "ClickSelf", "text": [ "确认调用", - "放弃调用" + "放弃调用", + "确认选择" ], "roi": [ 1105, 525, 175, 132 + ], + "preDelay": 1000, + "postDelay": 1000 + }, + "SSSHalfTimeDropsBegin": { + "algorithm": "JustReturn", + "action": "DoNothing", + "next": [ + "SSSHalfTimeDrops", + "SSSHalfTimeDropsCancel" + ] + }, + "SSSHalfTimeDrops": { + "algorithm": "OcrDetect", + "action": "ClickSelf", + "text": [], + "roi": [ + 206, + 452, + 897, + 88 + ], + "next": [ + "SSSHalfTimeDropsConfirm" + ] + }, + "SSSHalfTimeDropsConfirm": { + "algorithm": "OcrDetect", + "action": "ClickSelf", + "text": [ + "确认" + ], + "roi": [ + 1073, + 281, + 155, + 151 + ] + }, + "SSSHalfTimeDropsCancel": { + "algorithm": "OcrDetect", + "action": "ClickSelf", + "text": [ + "放弃" + ], + "roi": [ + 51, + 251, + 146, + 199 ] }, "ClickCornerUntilStartButton": { diff --git a/resource/template/SSSDropRecruitmentFlag.png b/resource/template/SSSDropRecruitmentFlag.png deleted file mode 100644 index 300c7920f5..0000000000 Binary files a/resource/template/SSSDropRecruitmentFlag.png and /dev/null differ diff --git a/src/MaaCore/Common/AsstBattleDef.h b/src/MaaCore/Common/AsstBattleDef.h index 665eb8e3f2..5acb70c69e 100644 --- a/src/MaaCore/Common/AsstBattleDef.h +++ b/src/MaaCore/Common/AsstBattleDef.h @@ -157,6 +157,7 @@ namespace asst::battle /* for SSS */ DrawCard, // “调配干员” CheckIfStartOver, // 检查如果没有某干员则退出重开 + GetDrops, // 识别并获取战斗中途的掉落物 }; struct Action @@ -212,6 +213,7 @@ namespace asst::battle std::vector strategies; bool draw_as_possible = false; int retry_times = 0; + std::vector order_of_drops; }; enum class EquipmentType @@ -231,8 +233,7 @@ namespace asst::battle copilot::OperUsageGroups groups; RoleCounts tool_men; - std::vector drop_buffs; - std::vector drop_tool_men; + std::vector order_of_drops; std::unordered_map stages_data; }; diff --git a/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp b/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp index 382e0a7fa6..6063d6ecd3 100644 --- a/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp +++ b/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp @@ -155,6 +155,14 @@ std::vector asst::CopilotConfig::parse_actions(co { "CHECKIFSTARTOVER", ActionType::CheckIfStartOver }, { "checkifstartover", ActionType::CheckIfStartOver }, { "检查重开", ActionType::CheckIfStartOver }, + + { "GetDrops", ActionType::GetDrops }, + { "Getdrops", ActionType::GetDrops }, + { "GETDROPS", ActionType::GetDrops }, + { "getdrops", ActionType::GetDrops }, + { "获取战利品", ActionType::GetDrops }, + { "获取掉落", ActionType::GetDrops }, + { "获取装备", ActionType::GetDrops }, }; std::string type_str = action_info.get("type", "Deploy"); diff --git a/src/MaaCore/Config/Miscellaneous/SSSCopilotConfig.cpp b/src/MaaCore/Config/Miscellaneous/SSSCopilotConfig.cpp index 1043c6ac54..f9aba5ba66 100644 --- a/src/MaaCore/Config/Miscellaneous/SSSCopilotConfig.cpp +++ b/src/MaaCore/Config/Miscellaneous/SSSCopilotConfig.cpp @@ -42,29 +42,13 @@ bool asst::SSSCopilotConfig::parse(const json::value& json) } } - if (auto drop_buffs = json.find("drop_buffs")) { - for (const auto& drop_buff : drop_buffs.value()) { - m_data.drop_buffs.emplace_back(drop_buff.as_string()); + if (auto drops_opt = json.find("drops")) { + m_data.order_of_drops.reserve(drops_opt->size()); + for (const auto& drop : *drops_opt) { + m_data.order_of_drops.emplace_back(drop.as_string()); } } - if (auto drop_tool_men = json.find("drop_tool_men")) { - for (const auto& man : drop_tool_men.value()) { - std::string name = man.as_string(); - if (auto role = get_role_type(name); role != Role::Unknown) { - m_data.drop_tool_men.emplace_back(name); - } - else if (BattleData.get_rarity(name) != 0) { - m_data.drop_tool_men.emplace_back(name); - } - else if (name == "None") { - m_data.drop_tool_men.emplace_back(name); - } - else { - Log.warn("Unknown drop tool man", name); - } - } - } for (const auto& stage : json.at("stages").as_array()) { CombatData stage_data; stage_data.info = CopilotConfig::parse_basic_info(stage); @@ -72,6 +56,7 @@ bool asst::SSSCopilotConfig::parse(const json::value& json) stage_data.actions = CopilotConfig::parse_actions(stage); stage_data.groups = m_data.groups; + stage_data.order_of_drops = m_data.order_of_drops; for (const auto& strategy_info : stage.at("strategies").as_array()) { Strategy strategy; diff --git a/src/MaaCore/Task/BattleHelper.cpp b/src/MaaCore/Task/BattleHelper.cpp index e13a4b1479..ea35e55547 100644 --- a/src/MaaCore/Task/BattleHelper.cpp +++ b/src/MaaCore/Task/BattleHelper.cpp @@ -86,14 +86,13 @@ bool asst::BattleHelper::update_deployment(bool init, const cv::Mat& reusable) LogTraceFunction; if (init) { - wait_until_start(); + wait_until_start(false); } cv::Mat image = init || reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable; if (init) { auto draw_future = std::async(std::launch::async, [&]() { save_map(image); }); - update_kills(image); } BattleImageAnalyzer oper_analyzer(image); @@ -219,11 +218,16 @@ bool asst::BattleHelper::update_deployment(bool init, const cv::Mat& reusable) AvatarCache.set_avatar(name, oper.role, oper.avatar); } } - pause(); if (!unknown_opers.empty()) { cancel_oper_selection(); } + + image = m_inst_helper.ctrler()->get_image(); + } + + if (init) { + update_kills(image); } check_in_battle(image); @@ -283,6 +287,10 @@ bool asst::BattleHelper::deploy_oper(const std::string& name, const Point& loc, // 1000 是随便取的一个系数,把整数的 pre_delay 转成小数用的 int duration = static_cast(dist / 1000.0 * swipe_oper_task_ptr->pre_delay); + // 时间太短了的压根放不上去,故意加长一点 + if (int min_duration = swipe_oper_task_ptr->special_params.at(3); duration < min_duration) { + duration = min_duration; + } bool deploy_with_pause = m_inst_helper.ctrler()->support_swipe_with_pause(); m_inst_helper.ctrler()->swipe(oper_rect, Rect(target_point.x, target_point.y, 1, 1), duration, false, swipe_oper_task_ptr->special_params.at(1), swipe_oper_task_ptr->special_params.at(2), @@ -380,38 +388,51 @@ bool asst::BattleHelper::check_pause_button(const cv::Mat& reusable) return ret; } -bool asst::BattleHelper::check_in_battle(const cv::Mat& reusable) +bool asst::BattleHelper::check_in_battle(const cv::Mat& reusable, bool weak) { cv::Mat image = reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable; - BattleImageAnalyzer analyzer(image); - m_in_battle = analyzer.analyze(); + if (weak) { + BattleImageAnalyzer analyzer(image); + m_in_battle = analyzer.analyze(); + } + else { + m_in_battle = check_pause_button(image); + } return m_in_battle; } -bool asst::BattleHelper::wait_until_start() +bool asst::BattleHelper::wait_until_start(bool weak) { LogTraceFunction; - while (!m_inst_helper.need_exit() && !check_in_battle()) { + cv::Mat image = m_inst_helper.ctrler()->get_image(); + while (!m_inst_helper.need_exit() && !check_in_battle(image, weak)) { + do_strategic_action(image); std::this_thread::yield(); + + image = m_inst_helper.ctrler()->get_image(); } return true; } -bool asst::BattleHelper::wait_until_end() +bool asst::BattleHelper::wait_until_end(bool weak) { LogTraceFunction; - while (!m_inst_helper.need_exit() && check_in_battle()) { - do_strategic_action(); + cv::Mat image = m_inst_helper.ctrler()->get_image(); + while (!m_inst_helper.need_exit() && check_in_battle(image, weak)) { + do_strategic_action(image); std::this_thread::yield(); + + image = m_inst_helper.ctrler()->get_image(); } return true; } bool asst::BattleHelper::do_strategic_action(const cv::Mat& reusable) { - return check_in_battle(reusable) && use_all_ready_skill(reusable); + cv::Mat image = reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable; + return check_in_battle(image) && use_all_ready_skill(image); } bool asst::BattleHelper::use_all_ready_skill(const cv::Mat& reusable) @@ -474,8 +495,8 @@ void asst::BattleHelper::save_map(const cv::Mat& image) auto draw = image.clone(); 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 - 30, info.pos.y), 1, 1.2, cv::Scalar(0, 0, 255), 2); + cv::circle(draw, cv::Point(info.pos.x, info.pos.y), 5, cv::Scalar(0, 255, 0), -1); + cv::putText(draw, loc.to_string(), cv::Point(info.pos.x - 30, info.pos.y), 1, 1.2, cv::Scalar(0, 0, 255), 2); } std::string suffix; @@ -579,7 +600,7 @@ bool asst::BattleHelper::move_camera(const std::pair& delta) // 还没转场的时候 if (m_kills != 0) { - wait_until_end(); + wait_until_end(false); } m_kills = 0; diff --git a/src/MaaCore/Task/BattleHelper.h b/src/MaaCore/Task/BattleHelper.h index 5c389e60c3..9c85e66b1c 100644 --- a/src/MaaCore/Task/BattleHelper.h +++ b/src/MaaCore/Task/BattleHelper.h @@ -45,9 +45,9 @@ namespace asst bool use_skill(const std::string& name, bool keep_waiting = true); bool use_skill(const Point& loc, bool keep_waiting = true); bool check_pause_button(const cv::Mat& reusable = cv::Mat()); - bool check_in_battle(const cv::Mat& reusable = cv::Mat()); - virtual bool wait_until_start(); - bool wait_until_end(); + bool check_in_battle(const cv::Mat& reusable = cv::Mat(), bool weak = false); + virtual bool wait_until_start(bool weak = true); + bool wait_until_end(bool weak = true); bool use_all_ready_skill(const cv::Mat& reusable = cv::Mat()); bool check_and_use_skill(const std::string& name, const cv::Mat& reusable = cv::Mat()); bool check_and_use_skill(const Point& loc, const cv::Mat& reusable = cv::Mat()); diff --git a/src/MaaCore/Task/Fight/StageDropsTaskPlugin.cpp b/src/MaaCore/Task/Fight/StageDropsTaskPlugin.cpp index a002e2eea3..adbed24c7d 100644 --- a/src/MaaCore/Task/Fight/StageDropsTaskPlugin.cpp +++ b/src/MaaCore/Task/Fight/StageDropsTaskPlugin.cpp @@ -209,13 +209,7 @@ void asst::StageDropsTaskPlugin::upload_to_penguin() { LogTraceFunction; - Log.warn("debug version, not upload to penguin"); - return; - - // https://github.com/MaaAssistantArknights/MaaAssistantArknights/pull/3290 - // 新的掉落识别算法,在确认识别结果完全准确前,暂时禁用上传功能 -#if 0 - if (m_server != "CN" && m_server != "US" && m_server != "JP") { + if (m_server != "CN" && m_server != "US" && m_server != "JP" && m_server != "KR") { return; } @@ -276,7 +270,6 @@ void asst::StageDropsTaskPlugin::upload_to_penguin() .set_extra_param(extra_param) .set_retry_times(5) .run(); -#endif } void asst::StageDropsTaskPlugin::report_penguin_callback(AsstMsg msg, const json::value& detail, AbstractTask* task_ptr) diff --git a/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp index a676e2700f..cd077c93ae 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp +++ b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp @@ -262,6 +262,9 @@ bool asst::BattleProcessTask::wait_condition(const Action& action) break; } } + if (!check_in_battle(image)) { + return false; + } do_strategy_and_update_image(); } } @@ -273,6 +276,9 @@ bool asst::BattleProcessTask::wait_condition(const Action& action) if (m_kills >= action.kills) { break; } + if (!check_in_battle(image)) { + return false; + } do_strategy_and_update_image(); } } @@ -284,6 +290,9 @@ bool asst::BattleProcessTask::wait_condition(const Action& action) if (m_cost >= action.costs) { break; } + if (!check_in_battle(image)) { + return false; + } do_strategy_and_update_image(); } } @@ -298,6 +307,9 @@ bool asst::BattleProcessTask::wait_condition(const Action& action) if (cooling_count == action.cooling) { break; } + if (!check_in_battle(image)) { + return false; + } do_strategy_and_update_image(); } } @@ -312,6 +324,9 @@ bool asst::BattleProcessTask::wait_condition(const Action& action) iter != m_cur_deployment_opers.cend() && iter->second.available) { break; } + if (!check_in_battle(image)) { + return false; + } do_strategy_and_update_image(); } } diff --git a/src/MaaCore/Task/SSS/SSSBattleProcessTask.cpp b/src/MaaCore/Task/SSS/SSSBattleProcessTask.cpp index f14de4297f..2e7e915f9b 100644 --- a/src/MaaCore/Task/SSS/SSSBattleProcessTask.cpp +++ b/src/MaaCore/Task/SSS/SSSBattleProcessTask.cpp @@ -1,6 +1,7 @@ #include "SSSBattleProcessTask.h" #include "Config/Miscellaneous/SSSCopilotConfig.h" +#include "Config/TaskData.h" #include "Controller.h" #include "Task/ProcessTask.h" #include "Utils/Logger.hpp" @@ -47,6 +48,8 @@ bool asst::SSSBattleProcessTask::do_derived_action(size_t action_index) return draw_card(); case battle::copilot::ActionType::CheckIfStartOver: return check_if_start_over(action); + case battle::copilot::ActionType::GetDrops: + return get_drops(); default: Log.error("unknown action type", static_cast(action.type)); return false; @@ -121,11 +124,12 @@ bool asst::SSSBattleProcessTask::do_strategic_action(const cv::Mat& reusable) return true; } -bool asst::SSSBattleProcessTask::wait_until_start() +bool asst::SSSBattleProcessTask::wait_until_start(bool weak) { LogTraceFunction; - return ProcessTask(*this, { "SSSFightDirectly" }).set_retry_times(300).run(); + return ProcessTask(*this, { "SSSFightDirectly" }).set_retry_times(300).run() && + BattleProcessTask::wait_until_start(weak); } bool asst::SSSBattleProcessTask::check_if_start_over(const battle::copilot::Action& action) @@ -161,9 +165,27 @@ bool asst::SSSBattleProcessTask::check_if_start_over(const battle::copilot::Acti bool asst::SSSBattleProcessTask::draw_card(bool with_retry) { + LogTraceFunction; + ProcessTask task(*this, { "SSSDrawCard" }); if (!with_retry) { task.set_retry_times(0); } return task.run(); } + +bool asst::SSSBattleProcessTask::get_drops() +{ + LogTraceFunction; + + const auto& drops = m_sss_combat_data.order_of_drops; + + // 不一定就有掉落界面,有可能宝箱怪压根没被打掉。所以不重试 + if (drops.empty()) { + return ProcessTask(*this, { inst_string() + "@SSSHalfTimeDropsCancel" }).set_retry_times(0).run(); + } + else { + Task.get(inst_string() + "@SSSHalfTimeDrops")->text = { drops }; + return ProcessTask(*this, { inst_string() + "@SSSHalfTimeDropsBegin" }).set_retry_times(0).run(); + } +} diff --git a/src/MaaCore/Task/SSS/SSSBattleProcessTask.h b/src/MaaCore/Task/SSS/SSSBattleProcessTask.h index dc031ebede..42b8bf1173 100644 --- a/src/MaaCore/Task/SSS/SSSBattleProcessTask.h +++ b/src/MaaCore/Task/SSS/SSSBattleProcessTask.h @@ -17,10 +17,11 @@ namespace asst virtual battle::copilot::CombatData& get_combat_data() override { return m_sss_combat_data; } virtual const std::string oper_name_ocr_task_name() const noexcept override { return "SSSBattleOperName"; } virtual bool need_to_wait_until_end() const noexcept override { return true; } - virtual bool wait_until_start() override; + virtual bool wait_until_start(bool weak = true) override; bool check_if_start_over(const battle::copilot::Action& action); bool draw_card(bool with_retry = true); + bool get_drops(); battle::sss::CombatData m_sss_combat_data; std::unordered_set m_all_cores; diff --git a/src/MaaCore/Task/SSS/SSSDropRewardsTaskPlugin.cpp b/src/MaaCore/Task/SSS/SSSDropRewardsTaskPlugin.cpp index 7846cbb54f..f28644c1de 100644 --- a/src/MaaCore/Task/SSS/SSSDropRewardsTaskPlugin.cpp +++ b/src/MaaCore/Task/SSS/SSSDropRewardsTaskPlugin.cpp @@ -44,7 +44,7 @@ bool asst::SSSDropRewardsTaskPlugin::_run() .ocr_res = result, .role = role == Role::Unknown ? std::nullopt : std::optional(role) }); } - for (const std::string& name : SSSCopilot.get_data().drop_tool_men) { + for (const std::string& name : SSSCopilot.get_data().order_of_drops) { auto role = get_role_type(name); bool is_role = role != Role::Unknown; auto iter = ranges::find_if(opers, [&](const DropRecruitment& props) {