mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-15 17:30:27 +08:00
feat: 分离不同肉鸽的招募、购物配置 (#2562)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -54,7 +54,6 @@ std::string asst::RoguelikeSkillSelectionImageAnalyzer::name_analyze(const Rect&
|
||||
analyzer.set_task_info(name_task_ptr);
|
||||
analyzer.set_image(m_image);
|
||||
analyzer.set_roi(roi.move(name_task_ptr->roi));
|
||||
analyzer.set_required(RoguelikeRecruit.get_oper_order());
|
||||
analyzer.set_replace(std::dynamic_pointer_cast<OcrTaskInfo>(Task.get("CharsNameOcrReplace"))->replace_map);
|
||||
|
||||
if (!analyzer.analyze()) {
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
|
||||
#include <meojson/json.hpp>
|
||||
|
||||
const asst::RoguelikeOperInfo& asst::RoguelikeRecruitConfiger::get_oper_info(const std::string& name) const noexcept
|
||||
|
||||
const asst::RoguelikeOperInfo& asst::RoguelikeRecruitConfiger::get_oper_info(const std::string& theme,
|
||||
const std::string& name) const noexcept
|
||||
{
|
||||
if (auto find_iter = m_all_opers.find(name); find_iter != m_all_opers.cend()) {
|
||||
auto& opers = m_all_opers.at(theme);
|
||||
if (auto find_iter = opers.find(name); find_iter != opers.cend()) {
|
||||
return find_iter->second;
|
||||
}
|
||||
else {
|
||||
@@ -16,10 +17,14 @@ const asst::RoguelikeOperInfo& asst::RoguelikeRecruitConfiger::get_oper_info(con
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::pair<int, int>> asst::RoguelikeRecruitConfiger::get_role_info(const BattleRole& role) const noexcept
|
||||
const std::vector<std::pair<int, int>> asst::RoguelikeRecruitConfiger::get_role_info(
|
||||
const std::string& theme, const BattleRole& role) const noexcept
|
||||
{
|
||||
if (role == BattleRole::Unknown) return std::vector<std::pair<int, int>>();
|
||||
if (auto iter = m_role_offset_map.find(role); iter != m_role_offset_map.end()) {
|
||||
if (role == BattleRole::Unknown) {
|
||||
return std::vector<std::pair<int, int>>();
|
||||
}
|
||||
auto& map = m_role_offset_map.at(theme);
|
||||
if (auto iter = map.find(role); iter != map.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return std::vector<std::pair<int, int>>();
|
||||
@@ -29,42 +34,46 @@ bool asst::RoguelikeRecruitConfiger::parse(const json::value& json)
|
||||
{
|
||||
clear();
|
||||
|
||||
for (const auto& role_name : json.at("roles").as_array()) {
|
||||
std::string str_role = role_name.as_string();
|
||||
const auto& role_json = json.at(str_role);
|
||||
std::vector<std::pair<int, int>> role_offset;
|
||||
if (auto opt = role_json.find<json::array>("role_priority_offset")) {
|
||||
for (const auto& offset : opt.value()) {
|
||||
std::pair<int, int> offset_pair = std::make_pair(offset[0].as_integer(), offset[1].as_integer());
|
||||
role_offset.emplace_back(offset_pair);
|
||||
}
|
||||
}
|
||||
m_role_offset_map.emplace(get_role_type(str_role), std::move(role_offset));
|
||||
for (const auto& oper_info : role_json.at("opers").as_array()) {
|
||||
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.recruit_priority_when_team_full =
|
||||
oper_info.get("recruit_priority_when_team_full", info.recruit_priority - 100);
|
||||
info.promote_priority_when_team_full =
|
||||
oper_info.get("promote_priority_when_team_full", info.promote_priority + 100);
|
||||
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));
|
||||
info.alternate_skill_usage = static_cast<BattleSkillUsage>(oper_info.get("alternate_skill_usage", 1));
|
||||
if (auto opt = oper_info.find<json::array>("recruit_priority_offset")) {
|
||||
for (const auto& theme_view : { RoguelikePhantomThemeName, RoguelikeMizukiThemeName }) {
|
||||
const std::string theme(theme_view);
|
||||
const auto& theme_json = json.at(theme);
|
||||
for (const auto& role_name : theme_json.at("roles").as_array()) {
|
||||
std::string str_role = role_name.as_string();
|
||||
const auto& role_json = theme_json.at(str_role);
|
||||
std::vector<std::pair<int, int>> role_offset;
|
||||
if (auto opt = role_json.find<json::array>("role_priority_offset")) {
|
||||
for (const auto& offset : opt.value()) {
|
||||
std::pair<int, int> offset_pair = std::make_pair(offset[0].as_integer(), offset[1].as_integer());
|
||||
info.recruit_priority_offset.emplace_back(offset_pair);
|
||||
role_offset.emplace_back(offset_pair);
|
||||
}
|
||||
}
|
||||
info.offset_melee = oper_info.get("offset_melee", false);
|
||||
m_role_offset_map[theme].emplace(get_role_type(str_role), std::move(role_offset));
|
||||
for (const auto& oper_info : role_json.at("opers").as_array()) {
|
||||
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.recruit_priority_when_team_full =
|
||||
oper_info.get("recruit_priority_when_team_full", info.recruit_priority - 100);
|
||||
info.promote_priority_when_team_full =
|
||||
oper_info.get("promote_priority_when_team_full", info.promote_priority + 100);
|
||||
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));
|
||||
info.alternate_skill_usage = static_cast<BattleSkillUsage>(oper_info.get("alternate_skill_usage", 1));
|
||||
if (auto opt = oper_info.find<json::array>("recruit_priority_offset")) {
|
||||
for (const auto& offset : opt.value()) {
|
||||
std::pair<int, int> offset_pair =
|
||||
std::make_pair(offset[0].as_integer(), offset[1].as_integer());
|
||||
info.recruit_priority_offset.emplace_back(offset_pair);
|
||||
}
|
||||
}
|
||||
info.offset_melee = oper_info.get("offset_melee", false);
|
||||
|
||||
m_all_opers.emplace(name, std::move(info));
|
||||
m_ordered_all_opers_name.emplace_back(name);
|
||||
m_all_opers[theme].emplace(name, std::move(info));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,5 +83,5 @@ bool asst::RoguelikeRecruitConfiger::parse(const json::value& json)
|
||||
void asst::RoguelikeRecruitConfiger::clear()
|
||||
{
|
||||
m_all_opers.clear();
|
||||
m_ordered_all_opers_name.clear();
|
||||
m_role_offset_map.clear();
|
||||
}
|
||||
|
||||
@@ -27,23 +27,24 @@ namespace asst
|
||||
BattleSkillUsage skill_usage = BattleSkillUsage::Possibly;
|
||||
BattleSkillUsage alternate_skill_usage = BattleSkillUsage::Possibly;
|
||||
};
|
||||
|
||||
class RoguelikeRecruitConfiger final : public SingletonHolder<RoguelikeRecruitConfiger>, public AbstractConfiger
|
||||
{
|
||||
public:
|
||||
virtual ~RoguelikeRecruitConfiger() override = default;
|
||||
|
||||
const RoguelikeOperInfo& get_oper_info(const std::string& name) const noexcept;
|
||||
const std::vector<std::pair<int, int>> get_role_info(const BattleRole& role) const noexcept;
|
||||
const auto& get_oper_order() const noexcept { return m_ordered_all_opers_name; }
|
||||
const RoguelikeOperInfo& get_oper_info(const std::string& theme, const std::string& name) const noexcept;
|
||||
const std::vector<std::pair<int, int>> get_role_info(const std::string& theme,
|
||||
const BattleRole& role) const noexcept;
|
||||
|
||||
protected:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
|
||||
void clear();
|
||||
|
||||
std::unordered_map<std::string, RoguelikeOperInfo> m_all_opers;
|
||||
std::unordered_map<BattleRole, std::vector<std::pair<int, int>>> m_role_offset_map;
|
||||
std::vector<std::string> m_ordered_all_opers_name;
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, RoguelikeOperInfo>> m_all_opers;
|
||||
std::unordered_map<std::string, std::unordered_map<BattleRole, std::vector<std::pair<int, int>>>>
|
||||
m_role_offset_map;
|
||||
};
|
||||
|
||||
inline static auto& RoguelikeRecruit = RoguelikeRecruitConfiger::get_instance();
|
||||
|
||||
@@ -6,37 +6,41 @@ bool asst::RoguelikeShoppingConfiger::parse(const json::value& json)
|
||||
{
|
||||
clear();
|
||||
|
||||
for (const auto& goods_json : json.as_array()) {
|
||||
std::string name = goods_json.at("name").as_string();
|
||||
for (const auto& theme_view : { RoguelikePhantomThemeName, RoguelikeMizukiThemeName }) {
|
||||
const std::string theme(theme_view);
|
||||
const auto& theme_json = json.at(theme);
|
||||
for (const auto& goods_json : theme_json.as_array()) {
|
||||
std::string name = goods_json.at("name").as_string();
|
||||
|
||||
std::vector<BattleRole> roles;
|
||||
if (auto roles_opt = goods_json.find<json::array>("roles")) {
|
||||
for (const auto& role_json : roles_opt.value()) {
|
||||
static const std::unordered_map<std::string, BattleRole> RoleMap = {
|
||||
{ "CASTER", BattleRole::Caster }, { "MEDIC", BattleRole::Medic },
|
||||
{ "PIONEER", BattleRole::Pioneer }, { "SNIPER", BattleRole::Sniper },
|
||||
{ "SPECIAL", BattleRole::Special }, { "SUPPORT", BattleRole::Support },
|
||||
{ "TANK", BattleRole::Tank }, { "WARRIOR", BattleRole::Warrior },
|
||||
};
|
||||
roles.emplace_back(RoleMap.at(role_json.as_string()));
|
||||
std::vector<BattleRole> roles;
|
||||
if (auto roles_opt = goods_json.find<json::array>("roles")) {
|
||||
for (const auto& role_json : roles_opt.value()) {
|
||||
static const std::unordered_map<std::string, BattleRole> RoleMap = {
|
||||
{ "CASTER", BattleRole::Caster }, { "MEDIC", BattleRole::Medic },
|
||||
{ "PIONEER", BattleRole::Pioneer }, { "SNIPER", BattleRole::Sniper },
|
||||
{ "SPECIAL", BattleRole::Special }, { "SUPPORT", BattleRole::Support },
|
||||
{ "TANK", BattleRole::Tank }, { "WARRIOR", BattleRole::Warrior },
|
||||
};
|
||||
roles.emplace_back(RoleMap.at(role_json.as_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<std::string> chars;
|
||||
if (auto chars_opt = goods_json.find<json::array>("chars")) {
|
||||
for (const auto& char_json : chars_opt.value()) {
|
||||
chars.emplace_back(char_json.as_string());
|
||||
std::vector<std::string> chars;
|
||||
if (auto chars_opt = goods_json.find<json::array>("chars")) {
|
||||
for (const auto& char_json : chars_opt.value()) {
|
||||
chars.emplace_back(char_json.as_string());
|
||||
}
|
||||
}
|
||||
|
||||
RoguelikeGoods goods;
|
||||
goods.name = std::move(name);
|
||||
goods.roles = std::move(roles);
|
||||
goods.chars = std::move(chars);
|
||||
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.at(theme).emplace_back(std::move(goods));
|
||||
}
|
||||
|
||||
RoguelikeGoods goods;
|
||||
goods.name = std::move(name);
|
||||
goods.roles = std::move(roles);
|
||||
goods.chars = std::move(chars);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -23,14 +23,14 @@ namespace asst
|
||||
public:
|
||||
virtual ~RoguelikeShoppingConfiger() override = default;
|
||||
|
||||
const auto& get_goods() const noexcept { return m_goods; }
|
||||
const auto& get_goods(const std::string& theme) const noexcept {return m_goods.at(theme); }
|
||||
|
||||
private:
|
||||
virtual bool parse(const json::value& json) override;
|
||||
|
||||
void clear();
|
||||
|
||||
std::vector<RoguelikeGoods> m_goods;
|
||||
std::unordered_map<std::string, std::vector<RoguelikeGoods>> m_goods;
|
||||
};
|
||||
|
||||
inline static auto& RoguelikeShopping = RoguelikeShoppingConfiger::get_instance();
|
||||
|
||||
@@ -132,7 +132,8 @@ bool asst::RoguelikeRecruitTaskPlugin::_run()
|
||||
}
|
||||
|
||||
// 查询招募配置
|
||||
auto& recruit_info = RoguelikeRecruit.get_oper_info(oper_info.name);
|
||||
auto& recruit_info = RoguelikeRecruit.get_oper_info(
|
||||
m_status->get_properties(RuntimeStatus::RoguelikeTheme).value(), oper_info.name);
|
||||
if (recruit_info.name.empty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -184,7 +185,8 @@ bool asst::RoguelikeRecruitTaskPlugin::_run()
|
||||
}
|
||||
}
|
||||
role_num = team_roles[oper_role];
|
||||
const auto role_info = RoguelikeRecruit.get_role_info(oper_role);
|
||||
const auto role_info = RoguelikeRecruit.get_role_info(
|
||||
m_status->get_properties(RuntimeStatus::RoguelikeTheme).value(), oper_role);
|
||||
for (const auto& offset_pair : ranges::reverse_view(role_info)) {
|
||||
if (role_num >= offset_pair.first) {
|
||||
priority += offset_pair.second;
|
||||
|
||||
@@ -93,7 +93,8 @@ bool asst::RoguelikeShoppingTaskPlugin::_run()
|
||||
|
||||
const auto& result = analyzer.get_result();
|
||||
bool bought = false;
|
||||
for (const auto& goods : RoguelikeShopping.get_goods()) {
|
||||
auto& all_goods = RoguelikeShopping.get_goods(m_status->get_properties(RuntimeStatus::RoguelikeTheme).value());
|
||||
for (const auto& goods : all_goods) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
@@ -166,4 +167,4 @@ bool asst::RoguelikeShoppingTaskPlugin::_run()
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,10 +47,12 @@ bool asst::RoguelikeSkillSelectionTaskPlugin::_run()
|
||||
int delay = Task.get("RoguelikeSkillSelectionMove1")->post_delay;
|
||||
bool has_rookie = false;
|
||||
for (const auto& [name, skill_vec] : analyzer.get_result()) {
|
||||
if (name.empty()) {
|
||||
const auto& oper_info =
|
||||
RoguelikeRecruit.get_oper_info(m_status->get_properties(RuntimeStatus::RoguelikeTheme).value(), name);
|
||||
if (oper_info.name.empty()) {
|
||||
Log.warn("Unknown oper", name);
|
||||
continue;
|
||||
}
|
||||
const auto& oper_info = RoguelikeRecruit.get_oper_info(name);
|
||||
|
||||
if (oper_info.alternate_skill > 0) {
|
||||
Log.info(__FUNCTION__, name, " select alternate skill:", oper_info.alternate_skill);
|
||||
@@ -89,4 +91,4 @@ bool asst::RoguelikeSkillSelectionTaskPlugin::_run()
|
||||
m_status->set_number(RuntimeStatus::RoguelikeTeamFullWithoutRookie, 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "RuntimeStatus.h"
|
||||
#include "Sub/ProcessTask.h"
|
||||
#include "Utils/Logger.hpp"
|
||||
#include "Utils/AsstBattleDef.h"
|
||||
|
||||
asst::RoguelikeTask::RoguelikeTask(const AsstCallback& callback, void* callback_arg)
|
||||
: PackageTask(callback, callback_arg, TaskType),
|
||||
@@ -38,21 +39,24 @@ asst::RoguelikeTask::RoguelikeTask(const AsstCallback& callback, void* callback_
|
||||
|
||||
bool asst::RoguelikeTask::set_params(const json::value& params)
|
||||
{
|
||||
std::string theme = params.get("theme", std::string(RoguelikePhantomThemeName));
|
||||
if (theme != RoguelikePhantomThemeName && theme != RoguelikeMizukiThemeName) {
|
||||
Log.error("Unknown roguelike theme", theme);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_status == nullptr) {
|
||||
m_roguelike_task_ptr->set_tasks({ "Stop" });
|
||||
Log.error(__FUNCTION__, "m_status is null");
|
||||
return false;
|
||||
}
|
||||
m_status->set_properties(RuntimeStatus::RoguelikeTheme, theme);
|
||||
m_roguelike_task_ptr->set_tasks({ theme + "@Roguelike@Begin" });
|
||||
|
||||
// 0 - 刷蜡烛,尽可能稳定地打更多层数
|
||||
// 1 - 刷源石锭,第一层投资完就退出
|
||||
// 2 - 【弃用】两者兼顾,投资过后再退出,没有投资就继续往后打
|
||||
// 3 - 尝试通关,激进策略(TODO)
|
||||
|
||||
std::string theme = params.get("theme", "Phantom");
|
||||
if (m_status == nullptr) {
|
||||
m_roguelike_task_ptr->set_tasks({ "Stop" });
|
||||
Log.error(__FUNCTION__, "| Cannot set roguelike name!");
|
||||
return false;
|
||||
}
|
||||
m_status->set_properties(RuntimeStatus::RoguelikeTheme, theme);
|
||||
theme += "@";
|
||||
m_roguelike_task_ptr->set_tasks({ theme + "Roguelike@Begin" });
|
||||
|
||||
int mode = params.get("mode", 0);
|
||||
switch (mode) {
|
||||
case 0:
|
||||
@@ -63,8 +67,9 @@ bool asst::RoguelikeTask::set_params(const json::value& params)
|
||||
m_roguelike_task_ptr->set_times_limit("StageTraderLeaveConfirm", 0, ProcessTask::TimesLimitType::Post);
|
||||
break;
|
||||
case 2:
|
||||
[[unlikely]]
|
||||
m_debug_task_ptr->set_enable(true);
|
||||
[[unlikely]] m_roguelike_task_ptr->set_times_limit("StageTraderInvestCancel", 0);
|
||||
m_roguelike_task_ptr->set_times_limit("StageTraderInvestCancel", 0);
|
||||
break;
|
||||
default:
|
||||
Log.error(__FUNCTION__, "| Unknown mode", mode);
|
||||
@@ -72,7 +77,7 @@ bool asst::RoguelikeTask::set_params(const json::value& params)
|
||||
}
|
||||
|
||||
int number_of_starts = params.get("starts_count", INT_MAX);
|
||||
m_roguelike_task_ptr->set_times_limit(theme + "Roguelike@StartExplore", number_of_starts);
|
||||
m_roguelike_task_ptr->set_times_limit(theme + "@Roguelike@StartExplore", number_of_starts);
|
||||
|
||||
bool investment_enabled = params.get("investment_enabled", true);
|
||||
if (!investment_enabled) {
|
||||
|
||||
@@ -222,4 +222,7 @@ namespace asst
|
||||
};
|
||||
|
||||
using BattleAttackRange = std::vector<Point>;
|
||||
|
||||
static constexpr std::string_view RoguelikePhantomThemeName = "Phantom";
|
||||
static constexpr std::string_view RoguelikeMizukiThemeName = "Mizuki";
|
||||
} // namespace asst
|
||||
|
||||
Reference in New Issue
Block a user