diff --git a/resource/copilot/SSS_Test.json b/resource/copilot/SSS_Test.json index c17800b757..6c09832f46 100644 --- a/resource/copilot/SSS_Test.json +++ b/resource/copilot/SSS_Test.json @@ -94,18 +94,6 @@ 4 ], "direction": "下" - }, - { - "kills": 1000, - "name": "桃金娘", - "location": [ - 5, - 4 - ], - "direction": "下" - }, - { - "type": "摆完挂机" } ], "retry_times": 3 diff --git a/resource/tasks.json b/resource/tasks.json index 8d1881a6e1..7d021b3146 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -9505,5 +9505,14 @@ 288, 144 ] + }, + "SSSDrawCard": { + "action": "ClickSelf", + "roi": [ + 1151, + 319, + 129, + 157 + ] } } diff --git a/resource/template/SSSDrawCard.png b/resource/template/SSSDrawCard.png new file mode 100644 index 0000000000..1ecbbe66d2 Binary files /dev/null and b/resource/template/SSSDrawCard.png differ diff --git a/src/MaaCore/Common/AsstBattleDef.h b/src/MaaCore/Common/AsstBattleDef.h index d7c4d81a20..f5ffb91050 100644 --- a/src/MaaCore/Common/AsstBattleDef.h +++ b/src/MaaCore/Common/AsstBattleDef.h @@ -156,7 +156,7 @@ namespace asst::battle int cost_changes = 0; int cooling = 0; ActionType type = ActionType::Deploy; - std::string group_name; // 目标名,若 type >= SwitchSpeed, group_name 为空 + std::string name; // 目标名,若 type >= SwitchSpeed, name 为空 Point location; DeployDirection direction = DeployDirection::Right; SkillUsage modify_usage = SkillUsage::NotUse; diff --git a/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp b/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp index 49baaa053f..775708f523 100644 --- a/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp +++ b/src/MaaCore/Config/Miscellaneous/CopilotConfig.cpp @@ -163,7 +163,7 @@ std::vector asst::CopilotConfig::parse_actions(co action.cost_changes = action_info.get("cost_changes", 0); action.costs = action_info.get("costs", 0); action.cooling = action_info.get("cooling", -1); - action.group_name = action_info.get("name", std::string()); + action.name = action_info.get("name", std::string()); action.location.x = action_info.get("location", 0, 0); action.location.y = action_info.get("location", 1, 0); diff --git a/src/MaaCore/MaaCore.vcxproj.filters b/src/MaaCore/MaaCore.vcxproj.filters index 3cb10169bf..68adfbfc4d 100644 --- a/src/MaaCore/MaaCore.vcxproj.filters +++ b/src/MaaCore/MaaCore.vcxproj.filters @@ -417,9 +417,6 @@ 源文件\Task\Miscellaneous - - 源文件\Task\Miscellaneous - 源文件\Task\Roguelike @@ -468,6 +465,9 @@ 源文件\Task\Miscellaneous + + 源文件\Task\Roguelike + diff --git a/src/MaaCore/Task/BattleHelper.cpp b/src/MaaCore/Task/BattleHelper.cpp index 089c1adaf2..f4154ee3c0 100644 --- a/src/MaaCore/Task/BattleHelper.cpp +++ b/src/MaaCore/Task/BattleHelper.cpp @@ -121,12 +121,17 @@ bool asst::BattleHelper::speed_up() return ProcessTask(this_task(), { "BattleSpeedUp" }).run(); } +bool asst::BattleHelper::abandon() +{ + return ProcessTask(this_task(), { "RoguelikeBattleExitBegin" }).run(); +} + bool asst::BattleHelper::update_deployment(bool init, const cv::Mat& reusable) { LogTraceFunction; if (init) { - wait_for_start(); + wait_until_start(); } cv::Mat image = init || reusable.empty() ? m_inst_helper.ctrler()->get_image() : reusable; @@ -406,7 +411,7 @@ bool asst::BattleHelper::check_pause_button() return battle_flag_analyzer.analyze(); } -bool asst::BattleHelper::wait_for_start() +bool asst::BattleHelper::wait_until_start() { LogTraceFunction; @@ -416,17 +421,22 @@ bool asst::BattleHelper::wait_for_start() return true; } -bool asst::BattleHelper::wait_for_end() +bool asst::BattleHelper::wait_until_end() { LogTraceFunction; while (!m_inst_helper.need_exit() && check_pause_button()) { - use_all_ready_skill(); + do_strategic_action(); std::this_thread::yield(); } return true; } +bool asst::BattleHelper::do_strategic_action(const cv::Mat& reusable) +{ + return use_all_ready_skill(reusable); +} + bool asst::BattleHelper::use_all_ready_skill(const cv::Mat& reusable) { bool used = false; diff --git a/src/MaaCore/Task/BattleHelper.h b/src/MaaCore/Task/BattleHelper.h index 682f1e195e..9ce41741a5 100644 --- a/src/MaaCore/Task/BattleHelper.h +++ b/src/MaaCore/Task/BattleHelper.h @@ -29,6 +29,7 @@ namespace asst virtual bool set_stage_name(const std::string& name); virtual void clear(); virtual const std::string oper_name_ocr_task_name() const noexcept { return "BattleOperName"; } + virtual bool do_strategic_action(const cv::Mat& reusable = cv::Mat()); bool calc_tiles_info(const std::string& stage_name); bool load_avatar_cache(const std::string& name, bool with_token = false); @@ -36,6 +37,7 @@ namespace asst bool pause(); bool speed_up(); + bool abandon(); bool update_deployment(bool init = false, const cv::Mat& reusable = cv::Mat()); bool update_kills(const cv::Mat& reusable = cv::Mat()); @@ -47,8 +49,8 @@ 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(); - bool wait_for_start(); - bool wait_for_end(); + bool wait_until_start(); + bool wait_until_end(); 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/Miscellaneous/BattleProcessTask.cpp b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp index bccc50ba0b..2b2a3a1b6d 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp +++ b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.cpp @@ -45,6 +45,10 @@ bool asst::BattleProcessTask::_run() do_action(i); } + if (need_to_wait_until_end()) { + wait_until_end(); + } + return true; } @@ -56,11 +60,6 @@ void asst::BattleProcessTask::clear() m_in_bullet_time = false; } -bool asst::BattleProcessTask::do_strategic_action(const cv::Mat& reusable) -{ - return use_all_ready_skill(reusable); -} - bool asst::BattleProcessTask::set_stage_name(const std::string& stage_name) { LogTraceFunction; @@ -122,7 +121,7 @@ bool asst::BattleProcessTask::to_group() m_oper_in_group.merge(ungrouped); for (const auto& action : m_combat_data.actions) { - const std::string& action_name = action.group_name; + const std::string& action_name = action.name; if (action_name.empty() || m_oper_in_group.contains(action_name)) { continue; } @@ -160,7 +159,7 @@ bool asst::BattleProcessTask::do_action(size_t action_index) } bool ret = false; - const std::string& name = m_oper_in_group[action.group_name]; + const std::string& name = m_oper_in_group[action.name]; const auto& location = action.location; switch (action.type) { @@ -189,7 +188,7 @@ bool asst::BattleProcessTask::do_action(size_t action_index) break; case ActionType::SkillUsage: - m_skill_usage[action.group_name] = action.modify_usage; + m_skill_usage[action.name] = action.modify_usage; ret = true; break; @@ -199,7 +198,7 @@ bool asst::BattleProcessTask::do_action(size_t action_index) break; case ActionType::SkillDaemon: - ret = wait_for_end(); + ret = wait_until_end(); break; default: ret = do_derived_action(action_index); @@ -223,7 +222,7 @@ void asst::BattleProcessTask::notify_action(const battle::copilot::Action& actio json::value info = basic_info_with_what("CopilotAction"); info["details"] |= json::object { { "action", ActionNames.at(action.type) }, - { "target", action.group_name }, + { "target", action.name }, { "doc", action.doc }, { "doc_color", action.doc_color }, }; @@ -296,7 +295,7 @@ bool asst::BattleProcessTask::wait_condition(const Action& action) // 部署干员还有额外等待费用够或 CD 转好 if (!m_in_bullet_time && action.type == ActionType::Deploy) { - const std::string& name = m_oper_in_group[action.group_name]; + const std::string& name = m_oper_in_group[action.name]; update_image_if_empty(); while (!need_exit()) { update_deployment(false, image); diff --git a/src/MaaCore/Task/Miscellaneous/BattleProcessTask.h b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.h index 2c40f324e7..d79ae23701 100644 --- a/src/MaaCore/Task/Miscellaneous/BattleProcessTask.h +++ b/src/MaaCore/Task/Miscellaneous/BattleProcessTask.h @@ -23,8 +23,8 @@ namespace asst virtual void clear() override; virtual bool do_derived_action([[maybe_unused]] size_t action_index) { return false; } - virtual bool do_strategic_action(const cv::Mat& reusable = cv::Mat()); virtual battle::copilot::CombatData& get_combat_data() { return m_combat_data; } + virtual bool need_to_wait_until_end() const { return false; } void load_cache(); bool to_group(); diff --git a/src/MaaCore/Task/Miscellaneous/SSSBattleProcessTask.cpp b/src/MaaCore/Task/Miscellaneous/SSSBattleProcessTask.cpp index 3b9cb0c120..1704cc6cb8 100644 --- a/src/MaaCore/Task/Miscellaneous/SSSBattleProcessTask.cpp +++ b/src/MaaCore/Task/Miscellaneous/SSSBattleProcessTask.cpp @@ -2,6 +2,7 @@ #include "Config/Miscellaneous/SSSCopilotConfig.h" #include "Controller.h" +#include "Task/ProcessTask.h" #include "Utils/Logger.hpp" using namespace asst::battle; @@ -46,9 +47,17 @@ bool asst::SSSBattleProcessTask::do_derived_action(size_t action_index) { LogTraceFunction; - std::ignore = action_index; + const auto& action = get_combat_data().actions.at(action_index); - return false; + switch (action.type) { + case battle::copilot::ActionType::DrawCard: + return draw_card(); + case battle::copilot::ActionType::CheckIfStartOver: + return check_if_start_over(action); + default: + Log.error("unknown action type", static_cast(action.type)); + return false; + } } bool asst::SSSBattleProcessTask::do_strategic_action(const cv::Mat& reusable) @@ -100,7 +109,47 @@ bool asst::SSSBattleProcessTask::do_strategic_action(const cv::Mat& reusable) } } + if (m_sss_combat_data.draw_as_possible) { + draw_card(); + } + use_all_ready_skill(image); return true; } + +bool asst::SSSBattleProcessTask::check_if_start_over(const battle::copilot::Action& action) +{ + LogTraceFunction; + + update_deployment(); + + bool to_abandon = false; + if (!action.name.empty() && !m_cur_deployment_opers.contains(action.name) && + !m_battlefield_opers.contains(action.name)) { + to_abandon = true; + } + else if (!action.role_counts.empty()) { + std::unordered_map cur_counts; + for (const auto& oper : m_cur_deployment_opers | views::values) { + cur_counts[oper.role] += 1; + } + for (const auto& [role, number] : action.role_counts) { + if (cur_counts[role] < number) { + to_abandon = true; + break; + } + } + } + + if (to_abandon) { + abandon(); + } + + return true; +} + +bool asst::SSSBattleProcessTask::draw_card() +{ + return ProcessTask(*this, { "SSSDrawCard" }).run(); +} diff --git a/src/MaaCore/Task/Miscellaneous/SSSBattleProcessTask.h b/src/MaaCore/Task/Miscellaneous/SSSBattleProcessTask.h index dd0a325c73..fd928e7fd3 100644 --- a/src/MaaCore/Task/Miscellaneous/SSSBattleProcessTask.h +++ b/src/MaaCore/Task/Miscellaneous/SSSBattleProcessTask.h @@ -17,6 +17,10 @@ namespace asst virtual bool do_strategic_action(const cv::Mat& reusable = cv::Mat()) override; virtual battle::copilot::CombatData& get_combat_data() { return m_sss_combat_data; } virtual const std::string oper_name_ocr_task_name() const noexcept { return "SSSBattleOperName"; } + virtual bool need_to_wait_until_end() const { return true; } + + bool check_if_start_over(const battle::copilot::Action& action); + bool draw_card(); battle::sss::CombatData m_sss_combat_data; std::unordered_set m_all_cores; diff --git a/src/MaaCore/Task/Roguelike/RoguelikeBattleTaskPlugin.cpp b/src/MaaCore/Task/Roguelike/RoguelikeBattleTaskPlugin.cpp index 6e3d1cce31..2463fd7f63 100644 --- a/src/MaaCore/Task/Roguelike/RoguelikeBattleTaskPlugin.cpp +++ b/src/MaaCore/Task/Roguelike/RoguelikeBattleTaskPlugin.cpp @@ -91,7 +91,7 @@ bool asst::RoguelikeBattleTaskPlugin::_run() return true; } -void asst::RoguelikeBattleTaskPlugin::wait_for_start_button_clicked() +void asst::RoguelikeBattleTaskPlugin::wait_until_start_button_clicked() { ProcessTask(*this, { "RoguelikeWaitForStartButtonClicked" }).set_task_delay(0).set_retry_times(0).run(); } @@ -110,7 +110,7 @@ bool asst::RoguelikeBattleTaskPlugin::calc_stage_info() { LogTraceFunction; - wait_for_start_button_clicked(); + wait_until_start_button_clicked(); clear(); bool calced = false; @@ -609,11 +609,6 @@ std::optional asst::RoguelikeBattleTaskPlugin::cal return best_oper; } -bool asst::RoguelikeBattleTaskPlugin::abandon() -{ - return ProcessTask(*this, { "RoguelikeBattleExitBegin" }).run(); -} - void asst::RoguelikeBattleTaskPlugin::all_melee_retreat() { for (const auto& loc : m_used_tiles | views::keys) { diff --git a/src/MaaCore/Task/Roguelike/RoguelikeBattleTaskPlugin.h b/src/MaaCore/Task/Roguelike/RoguelikeBattleTaskPlugin.h index 5a39cd7649..0e8bf112e5 100644 --- a/src/MaaCore/Task/Roguelike/RoguelikeBattleTaskPlugin.h +++ b/src/MaaCore/Task/Roguelike/RoguelikeBattleTaskPlugin.h @@ -34,7 +34,6 @@ namespace asst void load_cache(); void all_melee_retreat(); - bool abandon(); std::optional check_urgent(const std::unordered_set& pre_cooling, const std::unordered_set& cur_cooling, @@ -63,7 +62,7 @@ namespace asst battle::DeployDirection direction); void check_drone_tiles(); - void wait_for_start_button_clicked(); + void wait_until_start_button_clicked(); std::string oper_name_in_config(const battle::DeploymentOper& oper) const; battle::LocationType get_oper_location_type(const battle::DeploymentOper& oper) const;