Files
MaaAssistantArknights/src/MaaCore/Task/Roguelike/RoguelikeInvestTaskPlugin.cpp
status102 15c9a65a98 fix: 保存截图加回来
[skip changelog]
2025-08-12 14:42:12 +08:00

198 lines
7.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "RoguelikeInvestTaskPlugin.h"
#include "Config/TaskData.h"
#include "Controller/Controller.h"
#include "Task/ProcessTask.h"
#include "Task/Roguelike/RoguelikeControlTaskPlugin.h"
#include "Utils/Logger.hpp"
#include "Vision/RegionOCRer.h"
bool asst::RoguelikeInvestTaskPlugin::verify(AsstMsg msg, const json::value& details) const
{
if (msg != AsstMsg::SubTaskStart || details.get("subtask", std::string()) != "ProcessTask") {
return false;
}
if (m_invset_error) {
return false;
}
const auto& task_name = details.get("details", "task", "");
if (task_name.ends_with("Roguelike@StageTraderInvestConfirm")) {
return m_invest_count < m_maximum;
}
else {
return false;
}
}
bool asst::RoguelikeInvestTaskPlugin::load_params(const json::value& params)
{
m_maximum = params.get("investments_count", INT_MAX);
m_stop_when_full = params.get("stop_when_investment_full", false);
return true;
}
bool asst::RoguelikeInvestTaskPlugin::_run()
{
LogTraceFunction;
auto image = ctrler()->get_image();
int count = 0; // 当次已投资的个数
int retry = 0; // 重试次数
auto deposit = get_deposit(image); // 当前的存款
int count_limit = m_maximum - m_invest_count; // 可用投资次数
// 投资确认按钮
const auto& click_rect = Task.get("Roguelike@StageTraderInvest-Confirm")->specific_rect;
LogInfo << __FUNCTION__ << "开始投资, 存款" << deposit.value_or(-1) << ", 可投资次数" << count_limit;
while (!need_exit() && deposit && *deposit < 999 && count_limit - count > 0) {
int times = std::min(15, count_limit - count);
while (!need_exit() && times > 0) {
ctrler()->click(click_rect);
sleep(100);
times--;
}
if (count_limit - count < 5) {
sleep(500);
}
image = ctrler()->get_image();
if (is_investment_available(image)) { // 检查是否处于可投资状态
if (auto wallet = get_wallet(image); *wallet && *wallet == 0) { // 手头没钱了
Log.info(__FUNCTION__, "手头没钱了, 退出投资");
retry = 0;
while (!need_exit()) {
if (auto ocr = get_deposit(image); ocr) {
if (*ocr >= 0 && *ocr <= 999 && *ocr >= *deposit) {
count += *ocr - *deposit;
deposit = *ocr;
break;
}
}
if (retry++ > 5) {
Log.error(__FUNCTION__, "无法获取可投资状态下的存款");
save_img(utils::path("debug") / utils::path("roguelike") / utils::path("invest_system"));
break;
}
sleep(500);
image = ctrler()->get_image();
}
}
}
else if (is_investment_error(image)) {
m_invset_error = true;
Log.info(__FUNCTION__, "投资系统错误, 退出投资");
sleep(500); // 此处UI有一个从左往右的移动等待后重新截图防止UI错位
auto ocr = get_deposit_when_error(ctrler()->get_image());
if (ocr) {
// 可继续投资 / 到达投资上限999
count += *ocr - deposit.value_or(0);
deposit = *ocr;
}
else {
Log.error(__FUNCTION__, "无法获取错误状态下的存款");
save_img(utils::path("debug") / utils::path("roguelike") / utils::path("invest_system"));
}
break;
}
else {
Log.error(__FUNCTION__, "未知状态,投资中止");
return false;
}
}
const auto total = count + m_invest_count;
auto info = basic_info_with_what("RoguelikeInvestment");
info["details"]["count"] = count;
info["details"]["total"] = total;
info["details"]["deposit"] = deposit ? *deposit : -1;
callback(AsstMsg::SubTaskExtraInfo, info);
LogInfo << __FUNCTION__ << "本轮投资结束, 投资" << count << ", 共投资" << total << "; 系统余额"
<< (deposit ? *deposit : -1);
m_invest_count = total;
if (count_limit - count <= 0) {
Log.info(__FUNCTION__, "投资达到设置上限,", m_maximum);
auto cb = basic_info_with_what("RoguelikeInvestmentReachLimit");
cb["details"]["limit"] = m_maximum;
callback(AsstMsg::SubTaskExtraInfo, cb);
stop_roguelike();
return true;
}
if (deposit.value_or(0) == 999 && m_stop_when_full) {
Log.info(__FUNCTION__, "存款已满");
auto cb = basic_info_with_what("RoguelikeInvestmentReachFull");
callback(AsstMsg::SubTaskExtraInfo, cb);
stop_roguelike();
return true;
}
return true;
}
std::optional<int> asst::RoguelikeInvestTaskPlugin::ocr_count(const auto& img, const auto& task_name) const
{
const auto& number_replace = Task.get<OcrTaskInfo>("NumberOcrReplace")->replace_map;
auto task_replace = Task.get<OcrTaskInfo>(task_name)->replace_map;
auto merge_map = std::vector(number_replace);
ranges::copy(task_replace, std::back_inserter(merge_map));
RegionOCRer ocr(img);
ocr.set_task_info(task_name);
ocr.set_use_raw(false);
ocr.set_replace(merge_map);
if (!ocr.analyze()) {
Log.error(__FUNCTION__, "unable to analyze current investment count. task:", task_name);
return std::nullopt;
}
int count = 0;
if (!utils::chars_to_number(ocr.get_result().text, count)) {
LogError << __FUNCTION__ << "unable to convert current investment count<" << ocr.get_result().text
<< "> to number.";
return std::nullopt;
}
return count;
}
bool asst::RoguelikeInvestTaskPlugin::is_investment_available(const cv::Mat& image) const
{
auto task = ProcessTask(*this, { "Roguelike@StageTraderInvest-Arrow" });
task.set_reusable_image(image).set_task_delay(0).set_retry_times(0);
return task.run();
}
bool asst::RoguelikeInvestTaskPlugin::is_investment_error(const cv::Mat& image) const
{
auto task = ProcessTask(*this, { "Roguelike@StageTraderInvestSystemError" });
task.set_reusable_image(image)
.set_task_delay(0)
.set_times_limit("Roguelike@StageTraderInvestSystemError", 0)
.set_retry_times(0);
return task.run();
}
std::optional<int> asst::RoguelikeInvestTaskPlugin::get_deposit(const cv::Mat& image) const
{
return ocr_count(image, "Roguelike@StageTraderInvest-Deposit");
}
std::optional<int> asst::RoguelikeInvestTaskPlugin::get_deposit_when_error(const cv::Mat& image) const
{
return ocr_count(image, "Roguelike@StageTraderInvestError-Count");
}
std::optional<int> asst::RoguelikeInvestTaskPlugin::get_wallet(const cv::Mat& image) const
{
return ocr_count(image, "Roguelike@StageTraderInvest-Wallet");
}
void asst::RoguelikeInvestTaskPlugin::stop_roguelike() const
{
m_control_ptr->exit_then_stop(true);
m_task_ptr->set_enable(false);
}