feat.肉鸽新增支持skill_usage字段

This commit is contained in:
MistEO
2022-03-13 23:09:01 +08:00
parent e457795043
commit 9ff736aad4
10 changed files with 134 additions and 55 deletions

View File

@@ -130,6 +130,10 @@ TaskId ASSTAPI AsstAppendTask(AsstHandle handle, const char* type, const char* p
"skill": int, // 使用哪个技能,取值范围 [1, 3],可选项,默认 1
// 若设置为 3, 当 3 技能不可用时,会选择 2 技能
// 同理若设置为 2, 当 2 技能不可用时,会选择 1 技能(好像没有这种 case
"skill_usage": int // 技能用法,可选,默认 0
// 0 - 好了就用,有多少次用多少次(例如干员 棘刺 3 技能)
// 1 - 好了就用,仅使用一次(例如干员 山 2 技能)
// 2 - 关键时刻使用(例如干员 梓兰、芙蓉)
},
...
]

View File

@@ -3234,6 +3234,16 @@
100
]
},
"BattleOperName": {
"algorithm": "OcrDetect",
"text": [],
"roi": [
0,
160,
180,
60
]
},
"BattleUseOper": {
"algorithm": "JustReturn",
"preDelay": 500,
@@ -3925,6 +3935,7 @@
"Roguelike1RecruitData": {
"algorithm": "OcrDetect",
"text": [],
"Doc": "该任务的 ocrReplace 被所有涉及干员名的识别任务服用",
"ocrReplace": [
[
"白面.+",
@@ -4619,20 +4630,6 @@
"algorithm": "OcrDetect",
"text": [],
"action": "DoNothing",
"ocrReplace": [
[
"白面.+",
"白面鸮"
],
[
"蛇居箱",
"蛇屠箱"
],
[
".+刺",
"棘刺"
]
],
"rectMove": [
150,
-30,

View File

@@ -88,6 +88,10 @@ namespace asst
{
return x <= rhs.x && y <= rhs.y && (x + width) >= (rhs.x + rhs.width) && (y + height) >= (rhs.y + rhs.height);
}
bool include(const Point& rhs) const noexcept
{
return x <= rhs.x && y <= rhs.y && (x + width) >= rhs.x && (y + height) >= rhs.y;
}
std::string to_string() const
{
return "[ " + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(width) + ", " + std::to_string(height) + " ]";

View File

@@ -76,8 +76,6 @@ bool asst::Resource::load(const std::string& dir)
overload = true;
}
const auto& opt = m_general_cfg_unique_ins.get_options();
/* 加载模板图片资源 */
// task所需要的模板资源
m_templ_resource_unique_ins.append_load_required(TaskData::get_instance().get_templ_required());

View File

@@ -24,6 +24,11 @@ bool asst::RoguelikeBattleTaskPlugin::verify(AsstMsg msg, const json::value& det
}
}
void asst::RoguelikeBattleTaskPlugin::set_skill_usage(SkillUsageMap usage_map)
{
m_skill_usage = std::move(usage_map);
}
void asst::RoguelikeBattleTaskPlugin::set_stage_name(std::string stage)
{
m_stage_name = std::move(stage);
@@ -41,7 +46,7 @@ bool asst::RoguelikeBattleTaskPlugin::_run()
while (!need_exit()) {
// 不在战斗场景,且已使用过了干员,说明已经打完了,就结束循环
if (!auto_battle() && m_used_opers) {
if (!auto_battle() && m_opers_used) {
break;
}
}
@@ -78,6 +83,7 @@ bool asst::RoguelikeBattleTaskPlugin::get_stage_info()
continue;
}
m_side_tile_info = std::move(side_info);
m_normal_tile_info = tile.calc(tr.text, false);
m_stage_name = tr.text;
calced = true;
break;
@@ -140,20 +146,46 @@ bool asst::RoguelikeBattleTaskPlugin::auto_battle()
return false;
}
if (int hp = battle_analyzer.get_hp();
hp != 0) {
bool used_skills = false;
if (hp < m_pre_hp) { // 说明漏怪了,漏怪就开技能(
for (const Rect& rect : battle_analyzer.get_ready_skills()) {
used_skills = true;
if (!use_skill(rect)) {
break;
}
//if (int hp = battle_analyzer.get_hp();
// hp != 0) {
// bool used_skills = false;
// if (hp < m_pre_hp) { // 说明漏怪了,漏怪就开技能(
// for (const Rect& rect : battle_analyzer.get_ready_skills()) {
// used_skills = true;
// if (!use_skill(rect)) {
// break;
// }
// }
// }
// m_pre_hp = hp;
// if (used_skills) {
// return true;
// }
//}
for (const Rect& rect : battle_analyzer.get_ready_skills()) {
// 找出这个可以使用的技能是哪个干员的(根据之前放干员的位置)
std::string name = "NotFound";
for (const auto& [loc, oper_name] : m_used_tiles) {
auto point = m_normal_tile_info[loc].pos;
if (rect.include(point)) {
name = oper_name;
break;
}
}
m_pre_hp = hp;
if (used_skills) {
auto& usage = m_skill_usage[name];
Log.info("Oper", name, ", skill usage", static_cast<int>(usage));
switch (usage) {
case SkillUsage::Once:
use_skill(rect);
usage = SkillUsage::NotUse;
return true;
break;
case SkillUsage::Possibly:
use_skill(rect);
return true;
break;
}
}
@@ -200,6 +232,19 @@ bool asst::RoguelikeBattleTaskPlugin::auto_battle()
m_ctrler->click(opt_oper.rect);
sleep(use_oper_task_ptr->pre_delay);
OcrImageAnalyzer oper_name_analyzer(m_ctrler->get_image());
oper_name_analyzer.set_task_info(Task.get("BattleOperName"));
oper_name_analyzer.set_replace(
std::dynamic_pointer_cast<OcrTaskInfo>(
Task.get("Roguelike1RecruitData"))
->replace_map);
std::string oper_name = "Unknown";
if (oper_name_analyzer.analyze()) {
oper_name_analyzer.sort_result_by_score();
oper_name = oper_name_analyzer.get_result().front().text;
}
// 将干员拖动到场上
Loc loc = Loc::All;
switch (opt_oper.role) {
@@ -259,8 +304,8 @@ bool asst::RoguelikeBattleTaskPlugin::auto_battle()
m_ctrler->swipe(placed_point, end_point, swipe_oper_task_ptr->rear_delay);
m_used_tiles.emplace(placed_loc);
m_used_opers = true;
m_used_tiles.emplace(placed_loc, oper_name);
m_opers_used = true;
++m_cur_home_index;
return true;
@@ -283,7 +328,7 @@ bool asst::RoguelikeBattleTaskPlugin::use_skill(const asst::Rect& rect)
void asst::RoguelikeBattleTaskPlugin::clear()
{
m_used_opers = false;
m_opers_used = false;
m_pre_hp = 0;
m_homes.clear();
m_cur_home_index = 0;

View File

@@ -7,16 +7,26 @@
namespace asst
{
enum class SkillUsage
{
Possibly = 0, // 有就用,例如干员 棘刺 3 技能
Once = 1, // 只用一次,例如干员 银灰 2技能
InTime = 2, // 关键时刻使用,例如干员 假日威龙陈 3 技能
NotUse
};
class RoguelikeBattleTaskPlugin : public AbstractTaskPlugin
{
using Loc = asst::TilePack::BuildableType;
using Role = asst::BattleImageAnalyzer::Role;
public:
using SkillUsageMap = std::unordered_map<std::string, SkillUsage>;
public:
using AbstractTaskPlugin::AbstractTaskPlugin;
virtual ~RoguelikeBattleTaskPlugin() = default;
virtual bool verify(AsstMsg msg, const json::value& details) const override;
void set_skill_usage(SkillUsageMap usage_map);
void set_stage_name(std::string stage);
protected:
@@ -36,14 +46,16 @@ namespace asst
// 返回滑动的方向
Point calc_direction(Point loc, Role role);
bool m_used_opers = false;
bool m_opers_used = false;
int m_pre_hp = 0;
std::unordered_map<Point, TilePack::TileInfo> m_side_tile_info;
std::unordered_map<Point, TilePack::TileInfo> m_normal_tile_info;
std::vector<Point> m_homes;
size_t m_cur_home_index = 0;
std::unordered_set<Point> m_used_tiles;
std::unordered_map<Point, std::string> m_used_tiles;
std::string m_stage_name;
SkillUsageMap m_skill_usage;
};
}

View File

@@ -39,6 +39,10 @@ std::string asst::RoguelikeSkillSelectionImageAnalyzer::name_analyze(const Rect&
auto name_task_ptr = Task.get("Roguelike1SkillSelectionName");
analyzer.set_task_info(name_task_ptr);
analyzer.set_image(m_image, roi.move(name_task_ptr->rect_move));
analyzer.set_replace(
std::dynamic_pointer_cast<OcrTaskInfo>(
Task.get("Roguelike1RecruitData"))
->replace_map);
if (!analyzer.analyze()) {
return std::string();

View File

@@ -5,6 +5,7 @@
#include "RoguelikeBattleTaskPlugin.h"
#include "RoguelikeRecruitTaskPlugin.h"
#include "RoguelikeSkillSelectionTaskPlugin.h"
#include "RoguelikeBattleTaskPlugin.h"
#include "Logger.hpp"
@@ -16,7 +17,9 @@ asst::RoguelikeTask::RoguelikeTask(AsstCallback callback, void* callback_arg)
.set_retry_times(50);
m_roguelike_task_ptr->regiseter_plugin<RoguelikeFormationTaskPlugin>();
m_roguelike_task_ptr->regiseter_plugin<RoguelikeBattleTaskPlugin>();
m_battle_task_ptr = m_roguelike_task_ptr->regiseter_plugin<RoguelikeBattleTaskPlugin>();
m_recruit_task_ptr = m_roguelike_task_ptr->regiseter_plugin<RoguelikeRecruitTaskPlugin>();
m_recruit_task_ptr->set_retry_times(2);
@@ -41,6 +44,7 @@ bool asst::RoguelikeTask::set_params(const json::value& params)
std::vector<std::string> opers_vec;
RoguelikeSkillSelectionTaskPlugin::SkillMap skill_map;
RoguelikeBattleTaskPlugin::SkillUsageMap usage_map;
for (auto& oper : params.at("opers").as_array()) {
if (!oper.contains("name") || !oper.at("name").is_string()) {
@@ -53,6 +57,9 @@ bool asst::RoguelikeTask::set_params(const json::value& params)
std::string name = oper.at("name").as_string();
opers_vec.emplace_back(name);
skill_map.emplace(name, skill);
auto usage = static_cast<SkillUsage>(oper.get("skill_usage", 0));
usage_map.emplace(name, usage);
}
skill_map.emplace("Unknown", 3);
@@ -74,5 +81,7 @@ bool asst::RoguelikeTask::set_params(const json::value& params)
m_recruit_task_ptr->set_opers(std::move(opers_vec));
m_skill_task_ptr->set_skill_map(std::move(skill_map));
m_battle_task_ptr->set_skill_usage(std::move(usage_map));
return true;
}

View File

@@ -6,6 +6,7 @@ namespace asst
class ProcessTask;
class RoguelikeRecruitTaskPlugin;
class RoguelikeSkillSelectionTaskPlugin;
class RoguelikeBattleTaskPlugin;
class RoguelikeTask : public PackageTask
{
@@ -21,5 +22,6 @@ namespace asst
std::shared_ptr<ProcessTask> m_roguelike_task_ptr = nullptr;
std::shared_ptr<RoguelikeRecruitTaskPlugin> m_recruit_task_ptr = nullptr;
std::shared_ptr<RoguelikeSkillSelectionTaskPlugin> m_skill_task_ptr = nullptr;
std::shared_ptr<RoguelikeBattleTaskPlugin> m_battle_task_ptr = nullptr;
};
}

View File

@@ -24,7 +24,7 @@ int main(int argc, char** argv)
return -1;
}
bool connected = AsstConnect(ptr, "adb", "127.0.0.1:7555", "");
bool connected = AsstConnect(ptr, "adb", "127.0.0.1:5555", "");
if (!connected) {
std::cerr << "connect failed" << std::endl;
AsstDestroy(ptr);
@@ -37,11 +37,11 @@ int main(int argc, char** argv)
//AsstAppendTask(ptr, "StartUp", R"({})");
AsstAppendTask(ptr, "Fight", R"(
{
"stage": ""
}
)");
// AsstAppendTask(ptr, "Fight", R"(
//{
// "stage": "CE-5"
//}
// )");
// AsstAppendTask(ptr, "Recruit", R"(
//{
@@ -72,21 +72,25 @@ int main(int argc, char** argv)
//)");
// AsstAppendTask(ptr, "Award", R"({})");
//
// AsstAppendTask(ptr, "Roguelike", R"(
//{
// "opers": [
// {
// "name": "帕拉斯"
// },
// {
// "name": "梓兰"
// },
// {
// "name": "安赛尔"
// }
// ]
//}
//)");
AsstAppendTask(ptr, "Roguelike", R"(
{
"opers": [
{
"name": "棘刺",
"skill": 3,
"skill_usage": 1
},
{
"name": "梓兰"
},
{
"name": "芙蓉"
}
]
}
)");
//AsstAppendTask(ptr, "Debug", R"({})");
AsstStart(ptr);