diff --git a/resource/roguelike_shopping.json b/resource/roguelike_shopping.json index 670d1abfe1..8946f9dd82 100644 --- a/resource/roguelike_shopping.json +++ b/resource/roguelike_shopping.json @@ -1,22 +1,30 @@ [ { - "name": "金酒之杯" + "name": "金酒之杯", + "no_longer_buy": true, + "ignore_no_longer_buy": true }, { - "name": "投币玩具" + "name": "投币玩具", + "no_longer_buy": true, + "ignore_no_longer_buy": true }, { - "name": "骑士戒律·新编" + "name": "骑士戒律·新编", + "no_longer_buy": true, + "ignore_no_longer_buy": true }, { "name": "人事部密信" }, { - "name": "Miss.Christine摸摸券" + "name": "Miss.Christine摸摸券", + "promotion": 2 }, { "name": "残弩-典训", - "role": "SNIPER" + "role": "SNIPER", + "promotion": 1 }, { "name": "绿叶菜罐头" @@ -45,7 +53,8 @@ "name": "锈蚀的铁锤" }, { - "name": "尖笑鬼牌" + "name": "尖笑鬼牌", + "promotion": 1 }, { "name": "赤金的远征" @@ -70,7 +79,8 @@ }, { "name": "折戟-典训", - "role": "WARRIOR" + "role": "WARRIOR", + "promotion": 1 }, { "name": "全局作战文件" @@ -87,7 +97,8 @@ }, { "name": "钝爪-典训", - "role": "PIONEER" + "role": "PIONEER", + "promotion": 1 }, { "name": "皇家利口酒" @@ -104,7 +115,8 @@ }, { "name": "断杖-典训", - "role": "CASTER" + "role": "CASTER", + "promotion": 1 }, { "name": "高卢小圆饼" @@ -207,7 +219,8 @@ }, { "name": "支柱-典训", - "role": "SUPPORT" + "role": "SUPPORT", + "promotion": 1 }, { "name": "皇帝的收藏" @@ -219,7 +232,8 @@ "name": "香草沙士汽水" }, { - "name": "幸运硬币" + "name": "幸运硬币", + "ignore_no_longer_buy": true }, { "name": "镶金骨骰" @@ -238,7 +252,8 @@ "role": "PIONEER" }, { - "name": "至宝指环" + "name": "至宝指环", + "ignore_no_longer_buy": true }, { "name": "残弩-战场依存", @@ -396,7 +411,8 @@ "name": "凯旋号角" }, { - "name": "假面舞会面具" + "name": "假面舞会面具", + "ignore_no_longer_buy": true }, { "name": "奇渊面具" diff --git a/resource/tasks.json b/resource/tasks.json index 39950a8d88..d18c5136e2 100644 --- a/resource/tasks.json +++ b/resource/tasks.json @@ -6785,6 +6785,12 @@ 750, 280 ], + "rectMove": [ + -40, + -100, + 20, + 60 + ], "next": [ "Roguelike1TraderRandomShoppingConfirm", "Roguelike1TraderRandomShoppingCancel", @@ -6823,40 +6829,6 @@ ] }, - "Roguelike1TraderShoppingConfirm": { - "template": "Roguelike1TraderRandomShoppingConfirm.png", - "action": "ClickSelf", - "cache": false, - "roi": [ - 872, - 425, - 221, - 136 - ], - "rectMove": [ - -40, - -100, - 20, - 60 - ], - "rearDelay": 2000, - "Doc": "当网络卡的时候才会发生点了确认,但是还可以点取消的情况", - "next": [ - "Roguelike1TraderShoppingConfirmedFlag", - "Roguelike1ChooseOperFlag" - ] - }, - "Roguelike1TraderShoppingConfirmedFlag": { - "template": "Roguelike1StageTraderLeave.png", - "action": "DoNothing", - "cache": false, - "roi": [ - 1046, - 443, - 234, - 204 - ] - }, "Roguelike1TraderShoppingOver": { "template": "Roguelike1StageTraderLeave.png", "action": "ClickSelf", diff --git a/src/MeoAssistant/AsstBattleDef.h b/src/MeoAssistant/AsstBattleDef.h index 48d3df0921..4d52c62d55 100644 --- a/src/MeoAssistant/AsstBattleDef.h +++ b/src/MeoAssistant/AsstBattleDef.h @@ -102,7 +102,7 @@ namespace asst Rect rect; cv::Mat avatar; std::string name; - size_t index; + size_t index = 0; bool cooling = false; }; diff --git a/src/MeoAssistant/MeoAssistant.vcxproj b/src/MeoAssistant/MeoAssistant.vcxproj index 35bcc63408..b7070f3fb9 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj +++ b/src/MeoAssistant/MeoAssistant.vcxproj @@ -89,6 +89,7 @@ + @@ -178,6 +179,7 @@ + diff --git a/src/MeoAssistant/MeoAssistant.vcxproj.filters b/src/MeoAssistant/MeoAssistant.vcxproj.filters index a7883b5f22..aff2f6e5a3 100644 --- a/src/MeoAssistant/MeoAssistant.vcxproj.filters +++ b/src/MeoAssistant/MeoAssistant.vcxproj.filters @@ -363,6 +363,9 @@ 头文件\Task\Plugin\Roguelike + + 头文件\Task\Plugin\Roguelike + @@ -626,6 +629,9 @@ 源文件\Task\Plugin\Roguelike + + 源文件\Task\Plugin\Roguelike + diff --git a/src/MeoAssistant/ProcessTask.cpp b/src/MeoAssistant/ProcessTask.cpp index 86020c1701..51ac669607 100644 --- a/src/MeoAssistant/ProcessTask.cpp +++ b/src/MeoAssistant/ProcessTask.cpp @@ -95,14 +95,14 @@ bool ProcessTask::_run() }; Log.info(info.to_string()); - Rect rect; - auto front_task_ptr = Task.get(m_cur_tasks_name.front()); // 可能有配置错误,导致不存在对应的任务 if (front_task_ptr == nullptr) { Log.error("Invalid task", m_cur_tasks_name.front()); return false; } + + Rect rect; // 如果第一个任务是JustReturn的,那就没必要再截图并计算了 if (front_task_ptr->algorithm == AlgorithmType::JustReturn) { m_cur_task_ptr = front_task_ptr; diff --git a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp index 33155cb8c5..517a7c75b9 100644 --- a/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeRecruitTaskPlugin.cpp @@ -131,6 +131,15 @@ bool asst::RoguelikeRecruitTaskPlugin::check_core_char() void asst::RoguelikeRecruitTaskPlugin::select_oper(const BattleRecruitOperInfo& oper) { m_ctrler->click(oper.rect); + m_status->set_number(RuntimeStatus::RoguelikeCharElitePrefix + oper.name, oper.elite); m_status->set_number(RuntimeStatus::RoguelikeCharLevelPrefix + oper.name, oper.level); + + std::string overview_str = m_status->get_str(RuntimeStatus::RoguelikeCharOverview).value_or(json::value().to_string()); + json::value overview = json::parse(overview_str).value_or(json::value()); + overview[oper.name] = json::object{ + { "elite", oper.elite }, + { "level", oper.level }, + }; + m_status->set_str(RuntimeStatus::RoguelikeCharOverview, overview.to_string()); } diff --git a/src/MeoAssistant/RoguelikeResetTaskPlugin.cpp b/src/MeoAssistant/RoguelikeResetTaskPlugin.cpp new file mode 100644 index 0000000000..7d8e2d6458 --- /dev/null +++ b/src/MeoAssistant/RoguelikeResetTaskPlugin.cpp @@ -0,0 +1,26 @@ +#include "RoguelikeResetTaskPlugin.h" + +#include "RuntimeStatus.h" + +bool asst::RoguelikeResetTaskPlugin::verify(AsstMsg msg, const json::value& details) const +{ + if (msg != AsstMsg::SubTaskStart + || details.get("subtask", std::string()) != "ProcessTask") { + return false; + } + + if (details.at("details").at("task").as_string() == "Roguelike1Start") { + return true; + } + else { + return false; + } +} + +bool asst::RoguelikeResetTaskPlugin::_run() +{ + // 简单粗暴,后面如果多任务间有联动可能要改改 + m_status->clear_number(); + m_status->clear_str(); + return true; +} diff --git a/src/MeoAssistant/RoguelikeResetTaskPlugin.h b/src/MeoAssistant/RoguelikeResetTaskPlugin.h new file mode 100644 index 0000000000..e8483432a0 --- /dev/null +++ b/src/MeoAssistant/RoguelikeResetTaskPlugin.h @@ -0,0 +1,17 @@ +#pragma once +#include "AbstractTaskPlugin.h" + +namespace asst +{ + class RoguelikeResetTaskPlugin : public AbstractTaskPlugin + { + public: + using AbstractTaskPlugin::AbstractTaskPlugin; + virtual ~RoguelikeResetTaskPlugin() = default; + + virtual bool verify(AsstMsg msg, const json::value& details) const override; + + protected: + virtual bool _run() override; + }; +} diff --git a/src/MeoAssistant/RoguelikeShoppingConfiger.cpp b/src/MeoAssistant/RoguelikeShoppingConfiger.cpp index a4c59a8b2a..4d6e7b5034 100644 --- a/src/MeoAssistant/RoguelikeShoppingConfiger.cpp +++ b/src/MeoAssistant/RoguelikeShoppingConfiger.cpp @@ -4,8 +4,8 @@ bool asst::RoguelikeShoppingConfiger::parse(const json::value& json) { - for (const auto& commodity_json : json.as_array()) { - std::string name = commodity_json.at("name").as_string(); + for (const auto& goods_json : json.as_array()) { + std::string name = goods_json.at("name").as_string(); static const std::unordered_map RoleMap = { { "CASTER", BattleRole::Caster }, { "MEDIC", BattleRole::Medic }, @@ -17,11 +17,18 @@ bool asst::RoguelikeShoppingConfiger::parse(const json::value& json) { "WARRIOR", BattleRole::Warrior}, }; BattleRole role = BattleRole::Unknown; - std::string str_role = commodity_json.get("role", ""); + std::string str_role = goods_json.get("role", ""); if (!str_role.empty()) { role = RoleMap.at(str_role); } - m_goods.emplace_back(RoguelikeGoods{ name, role }); + RoguelikeGoods goods; + goods.name = std::move(name); + goods.role_restriction = role; + goods.promotion = goods_json.get("promotion", 0); + goods.no_longer_buy = goods_json.get("no_longer_buy", false); + goods.ignore_no_longer_buy = goods_json.get("ignore_no_longer_buy", false); + + m_goods.emplace_back(std::move(goods)); } return true; } diff --git a/src/MeoAssistant/RoguelikeShoppingConfiger.h b/src/MeoAssistant/RoguelikeShoppingConfiger.h index b743ea1164..e1f5ce30f5 100644 --- a/src/MeoAssistant/RoguelikeShoppingConfiger.h +++ b/src/MeoAssistant/RoguelikeShoppingConfiger.h @@ -11,7 +11,10 @@ namespace asst struct RoguelikeGoods { std::string name; - BattleRole restriction = BattleRole::Unknown; + BattleRole role_restriction = BattleRole::Unknown; + int promotion = 0; // 晋升 N 个干员 + bool no_longer_buy = false; + bool ignore_no_longer_buy = false; }; class RoguelikeShoppingConfiger : public AbstractConfiger diff --git a/src/MeoAssistant/RoguelikeShoppingTaskPlugin.cpp b/src/MeoAssistant/RoguelikeShoppingTaskPlugin.cpp index 99eada2515..ee536ac23e 100644 --- a/src/MeoAssistant/RoguelikeShoppingTaskPlugin.cpp +++ b/src/MeoAssistant/RoguelikeShoppingTaskPlugin.cpp @@ -5,6 +5,7 @@ #include "Controller.h" #include "ProcessTask.h" #include "Logger.hpp" +#include "RuntimeStatus.h" bool asst::RoguelikeShoppingTaskPlugin::verify(AsstMsg msg, const json::value& details) const { @@ -32,19 +33,55 @@ bool asst::RoguelikeShoppingTaskPlugin::_run() if (!analyzer.analyze()) { return false; } + + bool no_longer_buy = + m_status->get_number(RuntimeStatus::RoguelikeTraderNoLongerBuy).value_or(0) + ? true : false; + + 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()); + + std::unordered_map map_roles_count; + for (auto& [name, json_info] : json_chars_info.as_object()) { + int elite = static_cast(json_info.get("elite", 0)); + int level = static_cast(json_info.get("level", 0)); + Log.info(name, elite, level); + + // 等级太低的干员没必要为他专门买收藏品什么的 + if (elite * 1000 + level < 1070) { + continue; + } + + if (name == "阿米娅") { + map_roles_count[BattleRole::Caster] += 1; + map_roles_count[BattleRole::Warrior] += 1; + } + else { + BattleRole role = BattleRole::Unknown; + auto int_role = json_info.get("role", 0); + if (int_role) { + role = static_cast(int_role); + } + else { + role = Resrc.battle_data().get_role(name); + } + map_roles_count[role] += 1; + } + } + const auto& result = analyzer.get_result(); const auto& order_goods_list = Resrc.roguelike_shopping().get_goods(); - bool bought = false; for (const auto& goods : order_goods_list) { if (need_exit()) { return false; } - - if (goods.restriction != BattleRole::Unknown) { - // TODO + if (no_longer_buy && !goods.ignore_no_longer_buy) { continue; } + auto find_it = std::find_if(result.cbegin(), result.cend(), [&](const TextRect& tr) -> bool { return tr.text.find(goods.name) != std::string::npos || @@ -53,12 +90,23 @@ bool asst::RoguelikeShoppingTaskPlugin::_run() if (find_it == result.cend()) { continue; } + + if (goods.role_restriction != BattleRole::Unknown + && map_roles_count[goods.role_restriction] == 0) { + Log.trace("Ready to buy", goods.name, static_cast(goods.role_restriction), + ", but there is no such professional operator, skip"); + continue; + } + // 这里仅点一下收藏品,原本的 ProcessTask 还会再点一下,但它是由 rect_move 的,保证不会点出去 // 即 ProcessTask 多点的那一下会点到不影响的地方 // 然后继续走 next 里确认 or 取消等等的逻辑 Log.info("Ready to buy", goods.name); m_ctrler->click(find_it->rect); bought = true; + if (goods.no_longer_buy) { + m_status->set_number(RuntimeStatus::RoguelikeTraderNoLongerBuy, 1); + } break; } diff --git a/src/MeoAssistant/RoguelikeTask.cpp b/src/MeoAssistant/RoguelikeTask.cpp index 0acdfd8b45..f79c920a84 100644 --- a/src/MeoAssistant/RoguelikeTask.cpp +++ b/src/MeoAssistant/RoguelikeTask.cpp @@ -9,6 +9,7 @@ #include "RoguelikeControlTaskPlugin.h" #include "RoguelikeCustomStartTaskPlugin.h" #include "RoguelikeShoppingTaskPlugin.h" +#include "RoguelikeResetTaskPlugin.h" #include "Logger.hpp" @@ -21,6 +22,7 @@ asst::RoguelikeTask::RoguelikeTask(const AsstCallback& callback, void* callback_ m_roguelike_task_ptr->regiseter_plugin(); m_roguelike_task_ptr->regiseter_plugin(); + m_roguelike_task_ptr->regiseter_plugin(); m_roguelike_task_ptr->regiseter_plugin()->set_retry_times(0); m_custom_start_task_ptr = m_roguelike_task_ptr->regiseter_plugin(); diff --git a/src/MeoAssistant/RuntimeStatus.h b/src/MeoAssistant/RuntimeStatus.h index ffc01d45a9..6c5b2491cb 100644 --- a/src/MeoAssistant/RuntimeStatus.h +++ b/src/MeoAssistant/RuntimeStatus.h @@ -36,6 +36,8 @@ namespace asst static inline const std::string RoguelikeCharElitePrefix = "RoguelikeElite-"; static inline const std::string RoguelikeCharLevelPrefix = "RoguelikeLevel-"; static inline const std::string RoguelikeCharRarityPrefix = "RoguelikeRarity-"; + static inline const std::string RoguelikeCharOverview = "RoguelikeOverview"; + static inline const std::string RoguelikeTraderNoLongerBuy = "RoguelikeNoLongerBuy"; private: