mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-16 09:50:40 +08:00
Merge pull request #1569 from et2012/feat/roguelike_recruit
feat: 肉鸽招募支持跨职业优先级
This commit is contained in:
@@ -13,270 +13,394 @@
|
||||
"Warrior": [
|
||||
{
|
||||
"name": "帕拉斯",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 900,
|
||||
"promote_priority": 850
|
||||
},
|
||||
{
|
||||
"name": "Sharp",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 650,
|
||||
"promote_priority": 600
|
||||
},
|
||||
{
|
||||
"name": "艾丽妮",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 800,
|
||||
"promote_priority": 750
|
||||
},
|
||||
{
|
||||
"name": "煌",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 700,
|
||||
"promote_priority": 650
|
||||
},
|
||||
{
|
||||
"name": "山",
|
||||
"skill": 2,
|
||||
"skill_usage": 2
|
||||
"skill_usage": 2,
|
||||
"recruit_priority": 700,
|
||||
"promote_priority": 650
|
||||
},
|
||||
{
|
||||
"name": "羽毛笔",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 600,
|
||||
"promote_priority": 550
|
||||
},
|
||||
{
|
||||
"name": "银灰",
|
||||
"skill": 3,
|
||||
"alternate_skill": 1
|
||||
"alternate_skill": 1,
|
||||
"recruit_priority": 500,
|
||||
"promote_priority": 800
|
||||
},
|
||||
{
|
||||
"name": "陈",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 500,
|
||||
"promote_priority": 600
|
||||
},
|
||||
{
|
||||
"name": "拉普兰德",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 450,
|
||||
"promote_priority": 400
|
||||
},
|
||||
{
|
||||
"name": "幽灵鲨",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 450,
|
||||
"promote_priority": 400
|
||||
},
|
||||
{
|
||||
"name": "龙舌兰",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 400,
|
||||
"promote_priority": 400
|
||||
},
|
||||
{
|
||||
"name": "星极",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 400,
|
||||
"promote_priority": 400
|
||||
},
|
||||
{
|
||||
"name": "棘刺",
|
||||
"skill": 3,
|
||||
"alternate_skill": 1
|
||||
"alternate_skill": 1,
|
||||
"recruit_priority": 350,
|
||||
"promote_priority": 1000
|
||||
},
|
||||
{
|
||||
"name": "柏喙",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 350,
|
||||
"promote_priority": 300
|
||||
},
|
||||
{
|
||||
"name": "泡普卡",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 0
|
||||
},
|
||||
{
|
||||
"name": "月见夜",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 0
|
||||
},
|
||||
{
|
||||
"name": "玫兰莎",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 0
|
||||
}
|
||||
],
|
||||
"Pioneer": [
|
||||
{
|
||||
"name": "风笛",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 600,
|
||||
"promote_priority": 500
|
||||
},
|
||||
{
|
||||
"name": "芬",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 200,
|
||||
"promote_priority": 0
|
||||
},
|
||||
{
|
||||
"name": "桃金娘",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 200,
|
||||
"promote_priority": 550
|
||||
},
|
||||
{
|
||||
"name": "翎羽",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 0
|
||||
}
|
||||
],
|
||||
"Tank": [
|
||||
{
|
||||
"name": "泥岩",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 750,
|
||||
"promote_priority": 650
|
||||
},
|
||||
{
|
||||
"name": "塞雷娅",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 800,
|
||||
"promote_priority": 650
|
||||
},
|
||||
{
|
||||
"name": "斑点",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 100,
|
||||
"promote_priority": 0
|
||||
},
|
||||
{
|
||||
"name": "卡缇",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 80,
|
||||
"promote_priority": 0
|
||||
}
|
||||
],
|
||||
"Sniper": [
|
||||
{
|
||||
"name": "假日威龙陈",
|
||||
"skill": 3,
|
||||
"alternate_skill": 1
|
||||
"alternate_skill": 1,
|
||||
"recruit_priority": 900,
|
||||
"promote_priority": 900
|
||||
},
|
||||
{
|
||||
"name": "Stormeye",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 750,
|
||||
"promote_priority": 650
|
||||
},
|
||||
{
|
||||
"name": "能天使",
|
||||
"skill": 3,
|
||||
"alternate_skill": 1
|
||||
"alternate_skill": 1,
|
||||
"recruit_priority": 700,
|
||||
"promote_priority": 650
|
||||
},
|
||||
{
|
||||
"name": "空弦",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 650,
|
||||
"promote_priority": 600
|
||||
},
|
||||
{
|
||||
"name": "克洛丝",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 150,
|
||||
"promote_priority": 0
|
||||
},
|
||||
{
|
||||
"name": "安德切尔",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 100,
|
||||
"promote_priority": 0
|
||||
},
|
||||
{
|
||||
"name": "空爆",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 80,
|
||||
"promote_priority": 0
|
||||
}
|
||||
],
|
||||
"Caster": [
|
||||
{
|
||||
"name": "澄闪",
|
||||
"skill": 3,
|
||||
"alternate_skill": 2
|
||||
"alternate_skill": 2,
|
||||
"recruit_priority": 700,
|
||||
"promote_priority": 800
|
||||
},
|
||||
{
|
||||
"name": "Pith",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 600,
|
||||
"promote_priority": 600
|
||||
},
|
||||
{
|
||||
"name": "艾雅法拉",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 600,
|
||||
"promote_priority": 600
|
||||
},
|
||||
{
|
||||
"name": "阿米娅",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 500,
|
||||
"promote_priority": 500
|
||||
},
|
||||
{
|
||||
"name": "史都华德",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 100,
|
||||
"promote_priority": 0
|
||||
},
|
||||
{
|
||||
"name": "炎熔",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 80,
|
||||
"promote_priority": 0
|
||||
}
|
||||
],
|
||||
"Special": [
|
||||
{
|
||||
"name": "归溟幽灵鲨",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 700,
|
||||
"promote_priority": 700
|
||||
},
|
||||
{
|
||||
"name": "孑",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 80,
|
||||
"promote_priority": 600
|
||||
}
|
||||
],
|
||||
"Medic": [
|
||||
{
|
||||
"name": "凯尔希",
|
||||
"skill": 3,
|
||||
"alternate_skill": 2
|
||||
"alternate_skill": 2,
|
||||
"recruit_priority": 650,
|
||||
"promote_priority": 600
|
||||
},
|
||||
{
|
||||
"name": "Touch",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 600,
|
||||
"promote_priority": 500
|
||||
},
|
||||
{
|
||||
"name": "夜莺",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 550,
|
||||
"promote_priority": 450
|
||||
},
|
||||
{
|
||||
"name": "白面鸮",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 550,
|
||||
"promote_priority": 450
|
||||
},
|
||||
{
|
||||
"name": "桑葚",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 500,
|
||||
"promote_priority": 400
|
||||
},
|
||||
{
|
||||
"name": "蜜莓",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 700,
|
||||
"promote_priority": 1
|
||||
},
|
||||
{
|
||||
"name": "苏苏洛",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 500,
|
||||
"promote_priority": 400
|
||||
},
|
||||
{
|
||||
"name": "调香师",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 700,
|
||||
"promote_priority": 650
|
||||
},
|
||||
{
|
||||
"name": "安赛尔",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 100,
|
||||
"promote_priority": 0
|
||||
},
|
||||
{
|
||||
"name": "芙蓉",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 80,
|
||||
"promote_priority": 0
|
||||
}
|
||||
],
|
||||
"Support": [
|
||||
{
|
||||
"name": "灵知",
|
||||
"skill": 3,
|
||||
"alternate_skill": 1
|
||||
"alternate_skill": 1,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 500
|
||||
},
|
||||
{
|
||||
"name": "令",
|
||||
"skill": 3,
|
||||
"alternate_skill": 1
|
||||
"alternate_skill": 1,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 900
|
||||
},
|
||||
{
|
||||
"name": "铃兰",
|
||||
"skill": 3,
|
||||
"alternate_skill": 2
|
||||
"alternate_skill": 2,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 300
|
||||
},
|
||||
{
|
||||
"name": "安洁莉娜",
|
||||
"skill": 3,
|
||||
"alternate_skill": 2
|
||||
"alternate_skill": 2,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 200
|
||||
},
|
||||
{
|
||||
"name": "浊心斯卡蒂",
|
||||
"skill": 2
|
||||
"skill": 2,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 500
|
||||
},
|
||||
{
|
||||
"name": "梓兰",
|
||||
"skill": 1
|
||||
"skill": 1,
|
||||
"recruit_priority": 10,
|
||||
"promote_priority": 0
|
||||
}
|
||||
],
|
||||
"Alternate": [
|
||||
{
|
||||
"name": "预备干员-近战",
|
||||
"skill": 0
|
||||
"skill": 0,
|
||||
"recruit_priority": 5,
|
||||
"promote_priority": 0,
|
||||
"is_alternate": true
|
||||
},
|
||||
{
|
||||
"name": "预备干员-狙击",
|
||||
"skill": 0
|
||||
"skill": 0,
|
||||
"recruit_priority": 5,
|
||||
"promote_priority": 0,
|
||||
"is_alternate": true
|
||||
},
|
||||
{
|
||||
"name": "预备干员-术师",
|
||||
"skill": 0
|
||||
"skill": 0,
|
||||
"recruit_priority": 5,
|
||||
"promote_priority": 0,
|
||||
"is_alternate": true
|
||||
},
|
||||
{
|
||||
"name": "预备干员-后勤",
|
||||
"skill": 0
|
||||
"skill": 0,
|
||||
"recruit_priority": 5,
|
||||
"promote_priority": 0,
|
||||
"is_alternate": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4405,6 +4405,53 @@
|
||||
300
|
||||
]
|
||||
},
|
||||
"RoguelikeRecruitSwipeToTheLeftBegin": {
|
||||
"algorithm": "JustReturn",
|
||||
"action": "ClickRect",
|
||||
"specificRect": [
|
||||
1080,
|
||||
200,
|
||||
100,
|
||||
300
|
||||
],
|
||||
"preDelay": 300,
|
||||
"rearDelay": 1000,
|
||||
"maxTimes": 2,
|
||||
"Doc": "这里的preDelay作为滑动duration使用,rearDelay作为滑动额外延时使用,maxTimes作为重复次数使用"
|
||||
},
|
||||
"RoguelikeRecruitSwipeToTheLeftEnd": {
|
||||
"algorithm": "JustReturn",
|
||||
"action": "ClickRect",
|
||||
"specificRect": [
|
||||
400,
|
||||
200,
|
||||
100,
|
||||
300
|
||||
]
|
||||
},
|
||||
"RoguelikeRecruitSlowlySwipeRightRect": {
|
||||
"algorithm": "JustReturn",
|
||||
"action": "ClickRect",
|
||||
"specificRect": [
|
||||
780,
|
||||
200,
|
||||
100,
|
||||
300
|
||||
],
|
||||
"preDelay": 1500,
|
||||
"rearDelay": 300,
|
||||
"Doc": "这里的preDelay作为滑动duration使用,rearDelay作为滑动额外延时使用"
|
||||
},
|
||||
"RoguelikeRecruitSlowlySwipeLeftRect": {
|
||||
"algorithm": "JustReturn",
|
||||
"action": "ClickRect",
|
||||
"specificRect": [
|
||||
360,
|
||||
200,
|
||||
100,
|
||||
300
|
||||
]
|
||||
},
|
||||
"InfrastOperMoodProgressBar": {
|
||||
"template": "empty.png",
|
||||
"templThreshold": 160,
|
||||
|
||||
@@ -29,6 +29,9 @@ bool asst::RoguelikeRecruitConfiger::parse(const json::value& json)
|
||||
std::string name = oper_info.at("name").as_string();
|
||||
RoguelikeOperInfo info;
|
||||
info.name = name;
|
||||
info.recruit_priority = oper_info.get("recruit_priority", 0);
|
||||
info.promote_priority = oper_info.get("promote_priority", 0);
|
||||
info.is_alternate = oper_info.get("is_alternate", false);
|
||||
info.skill = oper_info.at("skill").as_integer();
|
||||
info.alternate_skill = oper_info.get("alternate_skill", 0);
|
||||
info.skill_usage = static_cast<BattleSkillUsage>(oper_info.get("skill_usage", 1));
|
||||
|
||||
@@ -15,6 +15,9 @@ namespace asst
|
||||
struct RoguelikeOperInfo
|
||||
{
|
||||
std::string name;
|
||||
int recruit_priority = 0; // 招募优先级 (0-1000)
|
||||
int promote_priority = 0; // 晋升优先级 (0-1000)
|
||||
bool is_alternate = false; // 是否后备干员 (允许重复招募、划到后备干员时不再往右划动)
|
||||
int skill = 0;
|
||||
int alternate_skill = 0;
|
||||
BattleSkillUsage skill_usage = BattleSkillUsage::Possibly;
|
||||
|
||||
@@ -38,76 +38,216 @@ bool asst::RoguelikeRecruitTaskPlugin::_run()
|
||||
recruited = true;
|
||||
};
|
||||
|
||||
const auto& recruit_cfg = Resrc.roguelike_recruit();
|
||||
|
||||
// 编队信息 (已有角色)
|
||||
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());
|
||||
const auto& chars_map = json_chars_info.as_object();
|
||||
|
||||
// 候选干员
|
||||
std::vector<RoguelikeRecruitInfo> recruit_list;
|
||||
|
||||
constexpr int SwipeTimes = 5;
|
||||
int i = 0;
|
||||
|
||||
// 翻页找出所有候选干员
|
||||
for (; i != SwipeTimes; ++i) {
|
||||
auto image = m_ctrler->get_image();
|
||||
RoguelikeRecruitImageAnalyzer analyzer(image);
|
||||
if (!analyzer.analyze()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& oper_list = analyzer.get_result();
|
||||
for (const auto& info : oper_list) {
|
||||
// 先看看有没有精二的
|
||||
if (info.elite != 2) {
|
||||
continue;
|
||||
}
|
||||
recruit_oper(info);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!recruited) {
|
||||
for (const auto& info : oper_list) {
|
||||
if (!info.required) {
|
||||
continue;
|
||||
}
|
||||
// 拿个精一 50 以上的
|
||||
if (info.elite == 0 ||
|
||||
(info.elite == 1 && info.level < 50)) {
|
||||
continue;
|
||||
}
|
||||
recruit_oper(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!recruited) {
|
||||
Log.info("All are lower");
|
||||
// 随便招个精一的
|
||||
for (const auto& info : oper_list) {
|
||||
if (!info.required) {
|
||||
continue;
|
||||
}
|
||||
if (info.elite == 0) {
|
||||
continue;
|
||||
}
|
||||
recruit_oper(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 这玩意选了也没啥用,不如省点理智
|
||||
//if (!recruited) {
|
||||
// // 随便招个
|
||||
// Log.info("All are very lower");
|
||||
// auto info = oper_list.front();
|
||||
// recruit_oper(info);
|
||||
//}
|
||||
|
||||
// 没有合适的干员,尝试向右翻页
|
||||
if (!recruited) {
|
||||
ProcessTask(*this, { "SlowlySwipeToTheRight" }).run();
|
||||
// 本页没有检测到符合条件的干员,向右滑动
|
||||
slowly_swipe(ProcessTaskAction::SlowlySwipeToTheRight);
|
||||
sleep(Task.get("Roguelike1Custom-HijackSquad")->rear_delay);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 已经招募到合适的干员
|
||||
return true;
|
||||
const auto& oper_list = analyzer.get_result();
|
||||
bool stop_swipe = false;
|
||||
|
||||
for (const auto& oper_info : oper_list) {
|
||||
// 查询招募配置
|
||||
auto& recruit_info = recruit_cfg.get_oper_info(oper_info.name);
|
||||
if (recruit_info.name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int priority = 0;
|
||||
|
||||
// 查询编队是否已持有该干员
|
||||
const auto& char_opt = chars_map.find(oper_info.name);
|
||||
|
||||
if (char_opt.has_value()) {
|
||||
// 干员已在编队中
|
||||
int elite = char_opt.value().get("elite", 0);
|
||||
if (elite == 2) {
|
||||
// 干员已精二,忽略
|
||||
continue;
|
||||
}
|
||||
|
||||
if (recruit_info.is_alternate) {
|
||||
// 预备干员可以重复招募
|
||||
priority = recruit_info.recruit_priority;
|
||||
}
|
||||
else {
|
||||
// 干员待晋升
|
||||
priority = recruit_info.promote_priority;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 干员待招募
|
||||
if (oper_info.elite == 2) {
|
||||
// TODO: 招募时已精二 (随机提升或对应分队) => promoted_priority
|
||||
priority = recruit_info.recruit_priority;
|
||||
}
|
||||
else {
|
||||
// 招募时未精二
|
||||
priority = recruit_info.recruit_priority;
|
||||
}
|
||||
}
|
||||
|
||||
// 已经划到后备干员,且已有候选干员,假定后面的干员优先级不会更高,不再划动
|
||||
if (recruit_info.is_alternate && !recruit_list.empty()) {
|
||||
stop_swipe = true;
|
||||
}
|
||||
|
||||
// 添加到候选名单
|
||||
auto existing_it = ranges::find_if(recruit_list, [&](const RoguelikeRecruitInfo& pri) -> bool {
|
||||
return pri.name == recruit_info.name;
|
||||
});
|
||||
if (existing_it == recruit_list.cend()) {
|
||||
RoguelikeRecruitInfo info;
|
||||
info.name = recruit_info.name;
|
||||
info.priority = priority;
|
||||
info.is_alternate = recruit_info.is_alternate;
|
||||
info.page_index = i;
|
||||
recruit_list.emplace_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
if (stop_swipe) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 向右滑动
|
||||
slowly_swipe(ProcessTaskAction::SlowlySwipeToTheRight);
|
||||
sleep(Task.get("Roguelike1Custom-HijackSquad")->rear_delay);
|
||||
}
|
||||
|
||||
Log.info(__FUNCTION__, "did not choose oper.");
|
||||
ProcessTask(*this, { "SwipeToTheLeft" }).set_times_limit("SwipeToTheLeft", i / 2 + 1).run();
|
||||
// 没有候选干员,进入后备逻辑
|
||||
if (recruit_list.empty()) {
|
||||
Log.trace(__FUNCTION__, "| No oper in recruit list.");
|
||||
|
||||
// 如果划动过,先划回最左边
|
||||
if (i != 0) {
|
||||
swipe_to_the_left_of_operlist(i / 2 + 1);
|
||||
}
|
||||
|
||||
auto image = m_ctrler->get_image();
|
||||
RoguelikeRecruitImageAnalyzer analyzer(image);
|
||||
if (!analyzer.analyze()) {
|
||||
Log.error(__FUNCTION__, "| Random recruitment analyse failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& oper_list = analyzer.get_result();
|
||||
|
||||
// 可能是晋升界面,随便选个精二的
|
||||
for (const auto& info : oper_list) {
|
||||
if (info.elite != 2) {
|
||||
continue;
|
||||
}
|
||||
Log.trace(__FUNCTION__, "| Choose random elite 2:", info.name, info.elite, info.level);
|
||||
recruit_oper(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 仍然没选,随便选个精一 50 以上的
|
||||
for (const auto& info : oper_list) {
|
||||
if (info.elite == 0 ||
|
||||
(info.elite == 1 && info.level < 50)) {
|
||||
continue;
|
||||
}
|
||||
Log.trace(__FUNCTION__, "| Choose random elite 1:", info.name, info.elite, info.level);
|
||||
recruit_oper(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
Log.trace(__FUNCTION__, "| Did not choose oper");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 选择优先级最高的干员
|
||||
auto selected_oper = ranges::max_element(recruit_list, std::less{}, std::mem_fn(&RoguelikeRecruitInfo::priority));
|
||||
if (selected_oper == recruit_list.cend()) {
|
||||
Log.trace(__FUNCTION__, "| No opers in recruit list.");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& char_name = selected_oper->name;
|
||||
Log.trace(__FUNCTION__, "| Top priority oper:", char_name, selected_oper->priority, "page", selected_oper->page_index, "/", i);
|
||||
|
||||
// 滑动方向
|
||||
// 页码大于一半: 从右往左划动
|
||||
// 页码小于一半: 划回最左边再往右
|
||||
bool is_rtl = false;
|
||||
|
||||
// 如果划动过,判断目标角色离哪个方向更近
|
||||
if (i != 0) {
|
||||
is_rtl = (selected_oper->page_index * 2) >= i;
|
||||
if (!is_rtl) {
|
||||
// 从左往右需要先划回最左边
|
||||
swipe_to_the_left_of_operlist(i / 2 + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return check_char(char_name, is_rtl);
|
||||
}
|
||||
|
||||
bool asst::RoguelikeRecruitTaskPlugin::check_char(const std::string& char_name, bool is_rtl)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
constexpr int SwipeTimes = 10;
|
||||
int i = 0;
|
||||
for (; i != SwipeTimes; ++i) {
|
||||
auto image = m_ctrler->get_image();
|
||||
RoguelikeRecruitImageAnalyzer analyzer(image);
|
||||
|
||||
// 只处理识别成功的情况,失败(无任何结果)时继续滑动
|
||||
if (analyzer.analyze()) {
|
||||
const auto& chars = analyzer.get_result();
|
||||
auto it = ranges::find_if(chars,
|
||||
[&](const BattleRecruitOperInfo& oper) -> bool {
|
||||
return oper.name == char_name;
|
||||
});
|
||||
|
||||
std::string oper_names = "";
|
||||
for (const auto& oper : chars) {
|
||||
if (!oper_names.empty()) {
|
||||
oper_names += ", ";
|
||||
}
|
||||
oper_names += oper.name;
|
||||
}
|
||||
Log.info(__FUNCTION__, "| Oper list:", oper_names);
|
||||
|
||||
if (it != chars.cend()) {
|
||||
select_oper(*it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// 没识别到目标干员,可能不在这一页,继续划动
|
||||
if (is_rtl) {
|
||||
slowly_swipe(ProcessTaskAction::SlowlySwipeToTheLeft);
|
||||
}
|
||||
else {
|
||||
slowly_swipe(ProcessTaskAction::SlowlySwipeToTheRight);
|
||||
}
|
||||
sleep(Task.get("Roguelike1Custom-HijackSquad")->rear_delay);
|
||||
}
|
||||
Log.info(__FUNCTION__, "| Cannot find oper `" + char_name + "`");
|
||||
swipe_to_the_left_of_operlist();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -120,40 +260,7 @@ bool asst::RoguelikeRecruitTaskPlugin::check_core_char()
|
||||
return false;
|
||||
}
|
||||
m_status->set_str("RoguelikeCoreChar", "");
|
||||
constexpr int SwipeTimes = 10;
|
||||
int i = 0;
|
||||
for (; i != SwipeTimes; ++i) {
|
||||
auto image = m_ctrler->get_image();
|
||||
RoguelikeRecruitImageAnalyzer analyzer(image);
|
||||
if (!analyzer.analyze()) {
|
||||
Log.info(__FUNCTION__, "| Unable to analyze image.");
|
||||
break;
|
||||
}
|
||||
const auto& chars = analyzer.get_result();
|
||||
auto it = ranges::find_if(chars,
|
||||
[&](const BattleRecruitOperInfo& oper) -> bool {
|
||||
return oper.name == core_opt.value();
|
||||
});
|
||||
|
||||
std::string oper_names = "";
|
||||
for (const auto& oper : chars) {
|
||||
if (!oper_names.empty()) {
|
||||
oper_names += ", ";
|
||||
}
|
||||
oper_names += oper.name;
|
||||
}
|
||||
Log.info(__FUNCTION__, "| Oper list:", oper_names);
|
||||
if (it == chars.cend()) {
|
||||
ProcessTask(*this, { "SlowlySwipeToTheRight" }).run();
|
||||
sleep(Task.get("Roguelike1Custom-HijackSquad")->rear_delay);
|
||||
continue;
|
||||
}
|
||||
select_oper(*it);
|
||||
return true;
|
||||
}
|
||||
Log.info(__FUNCTION__, "| Cannot find oper `" + core_opt.value() + "`");
|
||||
ProcessTask(*this, { "SwipeToTheLeft" }).run();
|
||||
return false;
|
||||
return check_char(core_opt.value());
|
||||
}
|
||||
|
||||
void asst::RoguelikeRecruitTaskPlugin::select_oper(const BattleRecruitOperInfo& oper)
|
||||
@@ -173,3 +280,41 @@ void asst::RoguelikeRecruitTaskPlugin::select_oper(const BattleRecruitOperInfo&
|
||||
};
|
||||
m_status->set_str(RuntimeStatus::RoguelikeCharOverview, overview.to_string());
|
||||
}
|
||||
|
||||
void asst::RoguelikeRecruitTaskPlugin::swipe_to_the_left_of_operlist(int loop_times)
|
||||
{
|
||||
LogTraceFunction;
|
||||
static Rect begin_rect = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->specific_rect; // 1080, 200, 100, 300
|
||||
static Rect end_rect = Task.get("RoguelikeRecruitSwipeToTheLeftEnd")->specific_rect; // 400, 200, 100, 300
|
||||
static int duration = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->pre_delay;
|
||||
static int extra_delay = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->rear_delay;
|
||||
static int cfg_loop_times = Task.get("RoguelikeRecruitSwipeToTheLeftBegin")->max_times;
|
||||
|
||||
for (int i = 0; i != cfg_loop_times * loop_times; ++i) {
|
||||
if (need_exit()) {
|
||||
return;
|
||||
}
|
||||
m_ctrler->swipe(end_rect, begin_rect, duration, true, 0, false);
|
||||
}
|
||||
sleep(extra_delay);
|
||||
}
|
||||
|
||||
void asst::RoguelikeRecruitTaskPlugin::slowly_swipe(ProcessTaskAction action)
|
||||
{
|
||||
LogTraceFunction;
|
||||
static Rect right_rect = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->specific_rect; // 780, 200, 100, 300
|
||||
static Rect left_rect = Task.get("RoguelikeRecruitSlowlySwipeLeftRect")->specific_rect; // 360, 200, 100, 300
|
||||
static int duration = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->pre_delay;
|
||||
static int extra_delay = Task.get("RoguelikeRecruitSlowlySwipeRightRect")->rear_delay;
|
||||
|
||||
switch (action) {
|
||||
case asst::ProcessTaskAction::SlowlySwipeToTheLeft:
|
||||
m_ctrler->swipe(left_rect, right_rect, duration, true, extra_delay, true);
|
||||
break;
|
||||
case asst::ProcessTaskAction::SlowlySwipeToTheRight:
|
||||
m_ctrler->swipe(right_rect, left_rect, duration, true, extra_delay, true);
|
||||
break;
|
||||
default: // 走不到这里
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,14 @@
|
||||
|
||||
namespace asst
|
||||
{
|
||||
// 干员招募信息
|
||||
struct RoguelikeRecruitInfo
|
||||
{
|
||||
std::string name; // 干员名字
|
||||
int priority = 0; // 招募优先级 (0-1000)
|
||||
int page_index = 0; // 所在页码 (用于判断翻页方向)
|
||||
bool is_alternate = false; // 是否后备干员 (允许重复招募、划到后备干员时不再往右划动)
|
||||
};
|
||||
class RoguelikeRecruitTaskPlugin : public AbstractTaskPlugin
|
||||
{
|
||||
public:
|
||||
@@ -15,9 +23,20 @@ namespace asst
|
||||
|
||||
protected:
|
||||
virtual bool _run() override;
|
||||
// 滑动到干员列表的最左侧
|
||||
void swipe_to_the_left_of_operlist(int loop_times = 1);
|
||||
// 缓慢向干员列表的左侧/右侧滑动
|
||||
void slowly_swipe(ProcessTaskAction action);
|
||||
|
||||
private:
|
||||
bool check_core_char();
|
||||
// 招募指定干员
|
||||
//
|
||||
// 输入参数:
|
||||
// char_name: 干员名称
|
||||
// is_rtl: 滑动方向 (true: 从右向左; false: 从左向右,需要先滑动到最左侧)
|
||||
// 返回值: 招募结果 (true: 成功; false: 失败)
|
||||
bool check_char(const std::string& char_name, bool is_rtl = false);
|
||||
void select_oper(const BattleRecruitOperInfo& oper);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user