mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 17:30:27 +08:00
feat.肉鸽新协议画饼,完成了读取配置部分的内容
This commit is contained in:
65
docs/肉鸽战斗流程协议.md
Normal file
65
docs/肉鸽战斗流程协议.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# 肉鸽战斗流程协议
|
||||
|
||||
`resource/roguelike/*.json` 的使用方法及各字段说明
|
||||
|
||||
## 完整字段一览
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"stage_name": "驯兽小屋", // 关卡名,必选
|
||||
"actions": [ // 战斗中的操作。有序,执行完前一个才会去执行下一个。必选
|
||||
{
|
||||
"type": "部署", // 操作类型,可选,默认 "Deploy"
|
||||
// "Deploy" | "Skill" | "Retreat" | "AllSkill"
|
||||
// "部署" | "技能" | "撤退" | "全部技能"
|
||||
// 中英文皆可,效果相同
|
||||
// 若为 "部署", 当费用不够时,会一直等待到费用够
|
||||
// 若为 "技能", 当技能 cd 没转好时,会直接跳过当前项。
|
||||
// 考虑不同干员技能效果及 cd 差异巨大,谨慎使用(例如 山 2 技能 这种,假如已经开了,你又开一次,就给关了)
|
||||
// "全部技能", 会一次性使用所有 skill_usgae == 3 的干员的技能
|
||||
|
||||
"kills": 0, // 击杀数条件,如果没达到就一直等待。可选,默认为 0。直接执行
|
||||
// TODO: 其他条件
|
||||
// TODO: "condition_type": 0, // 执行条件间的关系,可选,默认 0
|
||||
// // 0 - 且; 1 - 或
|
||||
|
||||
"roles": [ // 该位置使用的职业。可选,默认为空,任何职业都可以
|
||||
// 有序,会先使用靠前的职业
|
||||
// 会根据位置类型自动区分是高台还是地面。若设置了不可放置的职业,则忽略该职业
|
||||
// 如果这里面的职业一个都没有,则会跳过该位置转而执行下一条
|
||||
"近卫",
|
||||
"先锋",
|
||||
"重装",
|
||||
"召唤物"
|
||||
],
|
||||
|
||||
"waiting_cost": false, // 如果有 roles 中有靠前的职业,但费用不够,是否等待。可选,默认 false
|
||||
// 为 true 时,会使用 roles 中,当前有的、最靠前的职业(一直等他费用够)
|
||||
// 为 false 时,会使用 roles 中,当前有的、费用够的中最靠前的职业
|
||||
|
||||
"location": [ 5, 5 ], // 操作的干员的位置。必选
|
||||
|
||||
"direction": "左", // 部署干员的干员朝向。 type 为 "部署" 时必选
|
||||
// "Left" | "Right" | "Up" | "Down" | "None"
|
||||
// "左" | "右" | "上" | "下" | "无"
|
||||
// 中英文皆可,效果相同
|
||||
|
||||
"pre_delay": 0, // 前置延时。可选,默认 0, 单位毫秒
|
||||
"rear_delay": 0, // 后置延时。可选,默认 0, 单位毫秒
|
||||
|
||||
"timeout": 999999999 // 超时时间。当 type 为 "部署" 时可选。默认 INT_MAX, 单位毫秒
|
||||
// 等待超时则放弃当前动作, 转而执行下一个动作
|
||||
},
|
||||
{ // 简单举例
|
||||
"location": [6, 6],
|
||||
"roles": [
|
||||
"近卫",
|
||||
"先锋",
|
||||
"重装",
|
||||
"召唤物"
|
||||
],
|
||||
"direction": "左"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
54
resource/copilot/WD-EX-1.json
Normal file
54
resource/copilot/WD-EX-1.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"minimum_required": "v4.0",
|
||||
"desc": {
|
||||
"title": "《摆完挂机 简单好抄》",
|
||||
"details": "作业抄自 https://www.bilibili.com/video/BV12r4y1W7s4?p=10",
|
||||
"strategy_author": "萧然Q",
|
||||
"copilot_author": "Evil Deamo",
|
||||
"version": "v1.0"
|
||||
},
|
||||
"stage_name": "兽群战术",
|
||||
"opers": [
|
||||
{
|
||||
"name": "煌",
|
||||
"skill": 2
|
||||
}
|
||||
],
|
||||
"groups": [
|
||||
{
|
||||
"name": "普通单奶",
|
||||
"opers": [
|
||||
{
|
||||
"name": "闪灵",
|
||||
"skill": 2
|
||||
},
|
||||
{
|
||||
"name": "华法琳",
|
||||
"skill": 1
|
||||
},
|
||||
{
|
||||
"name": "赫默2",
|
||||
"skill": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"actions": [
|
||||
{
|
||||
"name": "煌",
|
||||
"location": [
|
||||
7,
|
||||
3
|
||||
],
|
||||
"direction": "左"
|
||||
},
|
||||
{
|
||||
"name": "普通单奶",
|
||||
"location": [
|
||||
9,
|
||||
4
|
||||
],
|
||||
"direction": "左"
|
||||
}
|
||||
]
|
||||
}
|
||||
28
resource/roguelike/意外.json
Normal file
28
resource/roguelike/意外.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"stage_name": "意外",
|
||||
"actions": [
|
||||
{
|
||||
"location": [
|
||||
5,
|
||||
3
|
||||
],
|
||||
"roles": [
|
||||
"近卫",
|
||||
"先锋",
|
||||
"重装",
|
||||
"召唤物"
|
||||
],
|
||||
"direction": "左"
|
||||
},
|
||||
{
|
||||
"location": [
|
||||
5,
|
||||
2
|
||||
],
|
||||
"roles": [
|
||||
"辅助"
|
||||
],
|
||||
"direction": "左"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -3923,9 +3923,7 @@
|
||||
100,
|
||||
255
|
||||
],
|
||||
"templThreshold": 0.95,
|
||||
"preDelay": 3000,
|
||||
"rearDelay": 3000
|
||||
"templThreshold": 0.95
|
||||
},
|
||||
"BattleSkillReady": {
|
||||
"roi": [
|
||||
|
||||
@@ -9,11 +9,18 @@ bool asst::AbstractConfiger::load(const std::string& filename)
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
if (!std::filesystem::exists(filename)) {
|
||||
#ifdef WIN32
|
||||
std::string cvt_filename = utils::utf8_to_gbk(filename);
|
||||
#else
|
||||
std::string cvt_filename = filename;
|
||||
#endif
|
||||
Log.info("Load:", cvt_filename);
|
||||
|
||||
if (!std::filesystem::exists(cvt_filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string content = utils::load_file_without_bom(filename);
|
||||
std::string content = utils::load_file_without_bom(cvt_filename);
|
||||
|
||||
auto&& ret = json::parser::parse(content);
|
||||
if (!ret) {
|
||||
|
||||
@@ -47,7 +47,8 @@ namespace asst
|
||||
Retreat, // 撤退干员
|
||||
SkillUsage, // 技能用法
|
||||
SwitchSpeed, // 切换二倍速
|
||||
BulletTime // 使用 1/5 的速度(点击任意干员),会在下一个任意操作后恢复原速度
|
||||
BulletTime, // 使用 1/5 的速度(点击任意干员),会在下一个任意操作后恢复原速度
|
||||
UseAllSkill // 使用所有技能,仅肉鸽模式
|
||||
};
|
||||
|
||||
struct BattleAction // 操作
|
||||
@@ -98,4 +99,17 @@ namespace asst
|
||||
return name == oper_name;
|
||||
}
|
||||
};
|
||||
|
||||
struct RoguelikeBattleAction
|
||||
{
|
||||
int kills = 0;
|
||||
BattleActionType type = BattleActionType::Deploy;
|
||||
std::vector<BattleRole> roles;
|
||||
bool waiting_cost = false;
|
||||
Point location;
|
||||
BattleDeployDirection direction = BattleDeployDirection::Right;
|
||||
int pre_delay = 0;
|
||||
int rear_delay = 0;
|
||||
int time_out = INT_MAX;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -79,7 +79,12 @@ bool asst::BattleProcessTask::analyze_opers_preview()
|
||||
std::string text = "( " + std::to_string(loc.x) + ", " + std::to_string(loc.y) + " )";
|
||||
cv::putText(draw, text, cv::Point(info.pos.x - 30, info.pos.y), 1, 1.2, cv::Scalar(0, 0, 255), 2);
|
||||
}
|
||||
cv::imwrite(utils::utf8_to_gbk(m_stage_name) + ".png", draw);
|
||||
#ifdef WIN32
|
||||
std::string output_filename = utils::utf8_to_gbk(m_stage_name);
|
||||
#else
|
||||
std::string output_filename = m_stage_name;
|
||||
#endif
|
||||
cv::imwrite(output_filename + ".png", draw);
|
||||
//#endif
|
||||
|
||||
// 干员头像出来之后,还要过 2 秒左右才可以点击,这里要加个延时
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace asst
|
||||
protected:
|
||||
virtual bool _run() override;
|
||||
|
||||
bool get_stage_info();
|
||||
virtual bool get_stage_info();
|
||||
bool battle_pause();
|
||||
bool battle_speedup();
|
||||
bool cancel_selection(); // 取消选择干员
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
<ClInclude Include="ProcessTask.h" />
|
||||
<ClInclude Include="ProcessTaskImageAnalyzer.h" />
|
||||
<ClInclude Include="RecruitConfiger.h" />
|
||||
<ClInclude Include="RoguelikeCopilotConfiger.h" />
|
||||
<ClInclude Include="RoguelikeFormationTaskPlugin.h" />
|
||||
<ClInclude Include="RoguelikeFormationImageAnalyzer.h" />
|
||||
<ClInclude Include="RoguelikeRecruitTaskPlugin.h" />
|
||||
@@ -147,6 +148,7 @@
|
||||
<ClCompile Include="ProcessTask.cpp" />
|
||||
<ClCompile Include="ProcessTaskImageAnalyzer.cpp" />
|
||||
<ClCompile Include="RecruitConfiger.cpp" />
|
||||
<ClCompile Include="RoguelikeCopilotConfiger.cpp" />
|
||||
<ClCompile Include="RoguelikeFormationTaskPlugin.cpp" />
|
||||
<ClCompile Include="RoguelikeFormationImageAnalyzer.cpp" />
|
||||
<ClCompile Include="RoguelikeRecruitTaskPlugin.cpp" />
|
||||
|
||||
@@ -318,6 +318,9 @@
|
||||
<ClInclude Include="CombatRecruitConfiger.h">
|
||||
<Filter>头文件\Resource</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RoguelikeCopilotConfiger.h">
|
||||
<Filter>头文件\Resource</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Controller.cpp">
|
||||
@@ -533,6 +536,9 @@
|
||||
<ClCompile Include="CombatRecruitConfiger.cpp">
|
||||
<Filter>源文件\Resource</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RoguelikeCopilotConfiger.cpp">
|
||||
<Filter>源文件\Resource</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\resource\config.json">
|
||||
|
||||
@@ -21,6 +21,7 @@ bool asst::Resource::load(const std::string& dir)
|
||||
constexpr static const char* ItemCfgFilename = "item_index.json";
|
||||
constexpr static const char* InfrastCfgFilename = "infrast.json";
|
||||
constexpr static const char* CopilotCfgDirname = "copilot";
|
||||
constexpr static const char* RoguelikeCfgDirname = "roguelike";
|
||||
constexpr static const char* OcrResourceFilename = "PaddleOCR";
|
||||
constexpr static const char* PenguinResourceFilename = "penguin-stats-recognize";
|
||||
constexpr static const char* TilesCalcResourceFilename = "Arknights-Tile-Pos";
|
||||
@@ -88,6 +89,16 @@ bool asst::Resource::load(const std::string& dir)
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(dir + RoguelikeCfgDirname)) {
|
||||
if (entry.path().extension() != ".json") {
|
||||
continue;
|
||||
}
|
||||
if (!m_roguelike_cfg_unique_ins.load(entry.path().u8string())) {
|
||||
m_last_error = entry.path().u8string() + " Load failed";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_infrast_cfg_unique_ins.load(dir + InfrastCfgFilename)) {
|
||||
if (!m_loaded) {
|
||||
m_last_error = std::string(InfrastCfgFilename) + ": " + m_infrast_cfg_unique_ins.get_last_error();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "TemplResource.h"
|
||||
#include "TilePack.h"
|
||||
#include "CopilotConfiger.h"
|
||||
#include "RoguelikeCopilotConfiger.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
@@ -60,6 +61,10 @@ namespace asst
|
||||
{
|
||||
return m_copilot_cfg_unique_ins;
|
||||
}
|
||||
RoguelikeCopilotConfiger& roguelike() noexcept
|
||||
{
|
||||
return m_roguelike_cfg_unique_ins;
|
||||
}
|
||||
OcrPack& ocr() noexcept
|
||||
{
|
||||
return m_ocr_pack_unique_ins;
|
||||
@@ -101,6 +106,10 @@ namespace asst
|
||||
{
|
||||
return m_copilot_cfg_unique_ins;
|
||||
}
|
||||
const RoguelikeCopilotConfiger& roguelike() const noexcept
|
||||
{
|
||||
return m_roguelike_cfg_unique_ins;
|
||||
}
|
||||
const OcrPack& ocr() const noexcept
|
||||
{
|
||||
return m_ocr_pack_unique_ins;
|
||||
@@ -125,6 +134,7 @@ namespace asst
|
||||
RecruitConfiger m_recruit_cfg_unique_ins;
|
||||
CombatRecruitConfiger m_combatrecruit_cfg_unique_ins;
|
||||
CopilotConfiger m_copilot_cfg_unique_ins;
|
||||
RoguelikeCopilotConfiger m_roguelike_cfg_unique_ins;
|
||||
ItemConfiger m_item_cfg_unique_ins;
|
||||
InfrastConfiger m_infrast_cfg_unique_ins;
|
||||
OcrPack m_ocr_pack_unique_ins;
|
||||
|
||||
@@ -37,7 +37,7 @@ bool asst::RoguelikeBattleTaskPlugin::_run()
|
||||
{
|
||||
bool getted_info = get_stage_info();
|
||||
|
||||
speed_up();
|
||||
//speed_up();
|
||||
|
||||
if (!getted_info) {
|
||||
return true;
|
||||
|
||||
161
src/MeoAssistant/RoguelikeCopilotConfiger.cpp
Normal file
161
src/MeoAssistant/RoguelikeCopilotConfiger.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
#include "RoguelikeCopilotConfiger.h"
|
||||
|
||||
#include <meojson/json.hpp>
|
||||
|
||||
#include "Logger.hpp"
|
||||
|
||||
bool asst::RoguelikeCopilotConfiger::parse(const json::value& json)
|
||||
{
|
||||
std::string stage_name = json.at("stage_name").as_string();
|
||||
|
||||
std::vector<RoguelikeBattleAction> actions_vec;
|
||||
|
||||
for (const auto& action_info : json.at("actions").as_array()) {
|
||||
RoguelikeBattleAction action;
|
||||
|
||||
static const std::unordered_map<std::string, BattleActionType> ActionTypeMapping = {
|
||||
{ "Deploy", BattleActionType::Deploy },
|
||||
{ "DEPLOY", BattleActionType::Deploy },
|
||||
{ "deploy", BattleActionType::Deploy },
|
||||
{ "部署", BattleActionType::Deploy },
|
||||
|
||||
{ "Skill", BattleActionType::UseSkill },
|
||||
{ "SKILL", BattleActionType::UseSkill },
|
||||
{ "skill", BattleActionType::UseSkill },
|
||||
{ "技能", BattleActionType::UseSkill },
|
||||
|
||||
{ "Retreat", BattleActionType::Retreat },
|
||||
{ "RETREAT", BattleActionType::Retreat },
|
||||
{ "retreat", BattleActionType::Retreat },
|
||||
{ "撤退", BattleActionType::Retreat },
|
||||
|
||||
{ "AllSkill", BattleActionType::UseAllSkill },
|
||||
{ "allskill", BattleActionType::UseAllSkill },
|
||||
{ "ALLSKILL", BattleActionType::UseAllSkill },
|
||||
{ "Allskill", BattleActionType::UseAllSkill },
|
||||
{ "全部技能", BattleActionType::UseAllSkill },
|
||||
};
|
||||
|
||||
std::string type_str = action_info.get("type", "Deploy");
|
||||
|
||||
if (auto iter = ActionTypeMapping.find(type_str);
|
||||
iter != ActionTypeMapping.end()) {
|
||||
action.type = iter->second;
|
||||
}
|
||||
else {
|
||||
action.type = BattleActionType::Deploy;
|
||||
}
|
||||
action.kills = action_info.get("kills", 0);
|
||||
|
||||
if (action_info.contains("roles")) {
|
||||
for (const auto& role_info : action_info.at("roles").as_array()) {
|
||||
static const std::unordered_map<std::string, BattleRole> RoleMapping = {
|
||||
{ "MEDIC", BattleRole::Medic },
|
||||
{ "Medic", BattleRole::Medic },
|
||||
{ "medic", BattleRole::Medic },
|
||||
{ "医疗", BattleRole::Medic },
|
||||
|
||||
{ "WARRIOR", BattleRole::Warrior },
|
||||
{ "Warrior", BattleRole::Warrior },
|
||||
{ "warrior", BattleRole::Warrior },
|
||||
{ "近卫", BattleRole::Warrior },
|
||||
|
||||
{ "SPECIAL", BattleRole::Special },
|
||||
{ "Special", BattleRole::Special },
|
||||
{ "special", BattleRole::Special },
|
||||
{ "特种", BattleRole::Special },
|
||||
|
||||
{ "SNIPER", BattleRole::Sniper },
|
||||
{ "Sniper", BattleRole::Sniper },
|
||||
{ "sniper", BattleRole::Sniper },
|
||||
{ "狙击", BattleRole::Sniper },
|
||||
|
||||
{ "PIONEER", BattleRole::Pioneer },
|
||||
{ "Pioneer", BattleRole::Pioneer },
|
||||
{ "pioneer", BattleRole::Pioneer },
|
||||
{ "先锋", BattleRole::Pioneer },
|
||||
|
||||
{ "TANK", BattleRole::Tank },
|
||||
{ "Tank", BattleRole::Tank },
|
||||
{ "tank", BattleRole::Tank },
|
||||
{ "重装", BattleRole::Tank },
|
||||
|
||||
{ "SUPPORT", BattleRole::Support },
|
||||
{ "Support", BattleRole::Support },
|
||||
{ "support", BattleRole::Support },
|
||||
{ "辅助", BattleRole::Support },
|
||||
|
||||
{ "CASTER", BattleRole::Caster },
|
||||
{ "Caster", BattleRole::Caster },
|
||||
{ "caster", BattleRole::Caster },
|
||||
{ "术师", BattleRole::Caster },
|
||||
|
||||
{ "Drone", BattleRole::Drone },
|
||||
{ "DRONE", BattleRole::Drone },
|
||||
{ "drone", BattleRole::Drone },
|
||||
{ "召唤物", BattleRole::Drone },
|
||||
{ "无人机", BattleRole::Drone }
|
||||
};
|
||||
|
||||
std::string role_name = role_info.as_string();
|
||||
if (auto iter = RoleMapping.find(role_name);
|
||||
iter != RoleMapping.end()) {
|
||||
action.roles.emplace_back(iter->second);
|
||||
}
|
||||
else {
|
||||
Log.error("Unknown role", role_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
action.location.x = action_info.get("location", 0, 0);
|
||||
action.location.y = action_info.get("location", 1, 0);
|
||||
|
||||
static const std::unordered_map<std::string, BattleDeployDirection> DeployDirectionMapping = {
|
||||
{ "Right", BattleDeployDirection::Right },
|
||||
{ "RIGHT", BattleDeployDirection::Right },
|
||||
{ "right", BattleDeployDirection::Right },
|
||||
{ "右", BattleDeployDirection::Right },
|
||||
|
||||
{ "Left", BattleDeployDirection::Left },
|
||||
{ "LEFT", BattleDeployDirection::Left },
|
||||
{ "left", BattleDeployDirection::Left },
|
||||
{ "左", BattleDeployDirection::Left },
|
||||
|
||||
{ "Up", BattleDeployDirection::Up },
|
||||
{ "UP", BattleDeployDirection::Up },
|
||||
{ "up", BattleDeployDirection::Up },
|
||||
{ "上", BattleDeployDirection::Up },
|
||||
|
||||
{ "Down", BattleDeployDirection::Down },
|
||||
{ "DOWN", BattleDeployDirection::Down },
|
||||
{ "down", BattleDeployDirection::Down },
|
||||
{ "下", BattleDeployDirection::Down },
|
||||
|
||||
{ "None", BattleDeployDirection::None },
|
||||
{ "NONE", BattleDeployDirection::None },
|
||||
{ "none", BattleDeployDirection::None },
|
||||
{ "无", BattleDeployDirection::None },
|
||||
};
|
||||
|
||||
std::string direction_str = action_info.get("direction", "Right");
|
||||
|
||||
if (auto iter = DeployDirectionMapping.find(direction_str);
|
||||
iter != DeployDirectionMapping.end()) {
|
||||
action.direction = iter->second;
|
||||
}
|
||||
else {
|
||||
action.direction = BattleDeployDirection::Right;
|
||||
}
|
||||
action.waiting_cost = action_info.get("waiting_cost", false);
|
||||
action.pre_delay = action_info.get("pre_delay", 0);
|
||||
action.rear_delay = action_info.get("rear_delay", 0);
|
||||
action.time_out = action_info.get("timeout", INT_MAX);
|
||||
|
||||
actions_vec.emplace_back(std::move(action));
|
||||
}
|
||||
|
||||
m_battle_actions[std::move(stage_name)] = std::move(actions_vec);
|
||||
|
||||
return true;
|
||||
}
|
||||
26
src/MeoAssistant/RoguelikeCopilotConfiger.h
Normal file
26
src/MeoAssistant/RoguelikeCopilotConfiger.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
#include "AbstractConfiger.h"
|
||||
|
||||
#include "AsstBattleDef.h"
|
||||
|
||||
namespace asst
|
||||
{
|
||||
class RoguelikeCopilotConfiger : public AbstractConfiger
|
||||
{
|
||||
public:
|
||||
virtual ~RoguelikeCopilotConfiger() = default;
|
||||
|
||||
bool contains_actions(const std::string& stage_name) const noexcept
|
||||
{
|
||||
return m_battle_actions.find(stage_name) != m_battle_actions.cend();
|
||||
}
|
||||
|
||||
auto get_actions(const std::string& stage_name) const noexcept
|
||||
{
|
||||
return m_battle_actions.at(stage_name);
|
||||
}
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
std::unordered_map<std::string, std::vector<RoguelikeBattleAction>> m_battle_actions;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user