feat: 新增根据队伍内已有同职业干员数量决定招募权重的选项

This commit is contained in:
DavidWang19
2022-10-26 18:53:53 +01:00
parent a1579d7449
commit d4dc680dcc
9 changed files with 212 additions and 54 deletions

View File

@@ -20,21 +20,53 @@
"promote_priority": 650,
"promote_priority_when_team_full": 750,
"promote_priority_when_team_full_Doc": "不填默认 promote_priority + 100",
"Doc": "编队满了且编队内所有干员 promote_priority 均大于200才会走两个 when_team_full 的逻辑"
"Doc": "编队满了且编队内所有干员 promote_priority 均大于200才会走两个 when_team_full 的逻辑",
"recruit_priority_offset": [
[
100,
100
],
[
200,
-200
]
],
"offset_doc": "队伍内已有100人同职业则权重+100200人-200已有数量从小到大"
},
{
"name": "海沫",
"skill": 1,
"recruit_priority": 960,
"recruit_priority": 500,
"promote_priority": 650,
"promote_priority_when_team_full": 750
"promote_priority_when_team_full": 750,
"recruit_priority_offset": [
[
0,
600
],
[
2,
-500
]
]
},
{
"name": "羽毛笔",
"skill": 1,
"recruit_priority": 950,
"recruit_priority": 490,
"promote_priority": 650,
"promote_priority_when_team_full": 750
"promote_priority_when_team_full": 750,
"recruit_priority_offset": [
[
0,
600
],
[
2,
-490
]
]
},
{
"name": "百炼嘉维尔",
@@ -47,17 +79,37 @@
"name": "棘刺",
"skill": 3,
"alternate_skill": 1,
"recruit_priority": 780,
"recruit_priority": 800,
"promote_priority": 1000,
"promote_priority_when_team_full": 1200
"promote_priority_when_team_full": 1200,
"recruit_priority_offset": [
[
1,
-780
],
[
2,
200
]
]
},
{
"name": "山",
"skill": 2,
"skill_usage": 2,
"recruit_priority": 750,
"recruit_priority": 400,
"promote_priority": 550,
"promote_priority_when_team_full": 750
"promote_priority_when_team_full": 750,
"recruit_priority_offset": [
[
0,
600
],
[
2,
-400
]
]
},
{
"name": "玛恩纳",
@@ -65,7 +117,17 @@
"alternate_skill": 2,
"recruit_priority": 750,
"promote_priority": 700,
"promote_priority_when_team_full": 750
"promote_priority_when_team_full": 750,
"recruit_priority_offset": [
[
0,
-750
],
[
4,
100
]
]
},
{
"name": "煌",
@@ -88,14 +150,30 @@
"alternate_skill": 1,
"recruit_priority": 750,
"promote_priority": 800,
"promote_priority_when_team_full": 800
"promote_priority_when_team_full": 800,
"recruit_priority_offset": [
[
3,
100
]
]
},
{
"name": "艾丽妮",
"skill": 3,
"alternate_skill": 1,
"recruit_priority": 750,
"promote_priority": 750
"promote_priority": 750,
"recruit_priority_offset": [
[
0,
-750
],
[
2,
200
]
]
},
{
"name": "陈",
@@ -321,14 +399,26 @@
"skill": 2,
"recruit_priority": 550,
"promote_priority": 550,
"promote_priority_when_team_full": 750
"promote_priority_when_team_full": 750,
"recruit_priority_offset": [
[
2,
-550
]
]
},
{
"name": "蓝毒",
"skill": 1,
"recruit_priority": 550,
"promote_priority": 550,
"promote_priority_when_team_full": 750
"promote_priority_when_team_full": 750,
"recruit_priority_offset": [
[
2,
-550
]
]
},
{
"name": "梅",

View File

@@ -81,34 +81,7 @@ bool asst::RoguelikeCopilotConfiger::parse(const json::value& json)
BattleRole::Warrior, BattleRole::Pioneer, BattleRole::Medic, BattleRole::Tank, BattleRole::Sniper,
BattleRole::Caster, BattleRole::Support, BattleRole::Special, BattleRole::Drone,
};
static const std::unordered_map<std::string, BattleRole> NameToRole = {
{ "warrior", BattleRole::Warrior }, { "WARRIOR", BattleRole::Warrior },
{ "Warrior", BattleRole::Warrior }, { "近卫", BattleRole::Warrior },
{ "pioneer", BattleRole::Pioneer }, { "PIONEER", BattleRole::Pioneer },
{ "Pioneer", BattleRole::Pioneer }, { "先锋", BattleRole::Pioneer },
{ "medic", BattleRole::Medic }, { "MEDIC", BattleRole::Medic },
{ "Medic", BattleRole::Medic }, { "医疗", BattleRole::Medic },
{ "tank", BattleRole::Tank }, { "TANK", BattleRole::Tank },
{ "Tank", BattleRole::Tank }, { "重装", BattleRole::Tank },
{ "sniper", BattleRole::Sniper }, { "SNIPER", BattleRole::Sniper },
{ "Sniper", BattleRole::Sniper }, { "狙击", BattleRole::Sniper },
{ "caster", BattleRole::Caster }, { "CASTER", BattleRole::Caster },
{ "Caster", BattleRole::Caster }, { "术师", BattleRole::Caster },
{ "support", BattleRole::Support }, { "SUPPORT", BattleRole::Support },
{ "Support", BattleRole::Support }, { "辅助", BattleRole::Support },
{ "special", BattleRole::Special }, { "SPECIAL", BattleRole::Special },
{ "Special", BattleRole::Special }, { "特种", BattleRole::Special },
{ "drone", BattleRole::Drone }, { "DRONE", BattleRole::Drone },
{ "Drone", BattleRole::Drone }, { "无人机", BattleRole::Drone },
};
auto to_lower = [](char c) -> char { return static_cast<char>(std::tolower(c)); };
if (auto opt = stage_info.find<json::array>("role_order")) {
const auto& raw_roles = opt.value();
@@ -126,19 +99,19 @@ bool asst::RoguelikeCopilotConfiger::parse(const json::value& json)
return std::move(name);
});
for (const std::string& role_name : roles) {
auto iter = NameToRole.find(role_name);
if (iter == NameToRole.end()) [[unlikely]] {
const auto role = get_role_type(role_name);
if (role == BattleRole::Unknown) [[unlikely]] {
Log.error("Unknown BattleRole:", role_name);
is_legal = false;
break;
}
if (specified_role.contains(iter->second)) [[unlikely]] {
if (specified_role.contains(role)) [[unlikely]] {
Log.error("Duplicated BattleRole:", role_name);
is_legal = false;
break;
}
specified_role.emplace(iter->second);
role_order.emplace_back(iter->second);
specified_role.emplace(role);
role_order.emplace_back(role);
}
if (is_legal) [[likely]] {
ranges::copy(RoleOrder | filter([&](BattleRole role) { return !specified_role.contains(role); }),
@@ -173,16 +146,16 @@ bool asst::RoguelikeCopilotConfiger::parse(const json::value& json)
Log.error("Unknown direction");
return false;
}
std::unordered_set<BattleRole> role;
std::unordered_set<BattleRole> fd_role;
for (auto& role_name : point["role"].as_array()) {
auto iter = NameToRole.find(role_name.as_string());
if (iter == NameToRole.end()) [[unlikely]] {
const auto role = get_role_type(role_name.as_string());
if (role == BattleRole::Unknown) [[unlikely]] {
Log.error("Unknown role name:", role_name);
return false;
}
role.emplace(iter->second);
fd_role.emplace(role);
}
fd_dir.role = std::move(role);
fd_dir.role = std::move(fd_role);
data.force_deploy_direction.emplace(location, fd_dir);
}
}

View File

@@ -37,6 +37,12 @@ bool asst::RoguelikeRecruitConfiger::parse(const json::value& json)
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);
}
}
m_all_opers.emplace(name, std::move(info));
m_ordered_all_opers_name.emplace_back(name);

View File

@@ -19,6 +19,7 @@ namespace asst
int promote_priority = 0; // 晋升优先级 (0-1000)
int recruit_priority_when_team_full = 0; // 队伍满时的招募优先级 (0-1000)
int promote_priority_when_team_full = 0; // 队伍满时的晋升优先级 (0-1000)
std::vector<std::pair<int, int>> recruit_priority_offset;
bool is_alternate = false; // 是否后备干员 (允许重复招募、划到后备干员时不再往右划动)
int skill = 0;
int alternate_skill = 0;

View File

@@ -45,6 +45,7 @@ namespace asst
static inline const std::string RoguelikeTraderNoLongerBuy = "RoguelikeNoLongerBuy";
static inline const std::string RoguelikeSkillUsagePrefix = "RoguelikeSkillUsage-";
static inline const std::string RoguelikeTeamFullWithoutRookie = "RoguelikeTeamFullWithoutRookie";
static inline const std::string RoguelikeTeamRoles = "RoguelikeTeamRoles";
static inline const std::string RoguelikeTheme = "RoguelikeTheme";
private:

View File

@@ -4,6 +4,7 @@
#include "Controller.h"
#include "ImageAnalyzer/RoguelikeRecruitImageAnalyzer.h"
#include "Resource/RoguelikeRecruitConfiger.h"
#include "Resource/BattleDataConfiger.h"
#include "RuntimeStatus.h"
#include "TaskData.h"
#include "Utils/Logger.hpp"
@@ -33,6 +34,11 @@ bool asst::RoguelikeRecruitTaskPlugin::verify(AsstMsg msg, const json::value& de
}
}
std::string asst::RoguelikeRecruitTaskPlugin::get_oper_role(const std::string& name)
{
return std::to_string(BattleData.get_role(name));
}
bool asst::RoguelikeRecruitTaskPlugin::_run()
{
LogTraceFunction;
@@ -56,6 +62,9 @@ bool asst::RoguelikeRecruitTaskPlugin::_run()
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::string teamroles_str =
m_status->get_str(RuntimeStatus::RoguelikeTeamRoles).value_or(json::value().to_string());
json::value teamroles = json::parse(teamroles_str).value_or(json::value());
// 候选干员
std::vector<RoguelikeRecruitInfo> recruit_list;
@@ -153,6 +162,13 @@ bool asst::RoguelikeRecruitTaskPlugin::_run()
Log.trace(__FUNCTION__, "| Ignored low level oper:", oper_info.name, oper_info.elite,
oper_info.level);
}
int role_num = teamroles.get(get_oper_role(oper_info.name), 0);
for (const auto& offset_pair : ranges::reverse_view(recruit_info.recruit_priority_offset)) {
if (role_num >= offset_pair.first) {
priority += offset_pair.second;
break;
}
}
}
// 优先级为0可能练度不够被忽略
@@ -246,7 +262,7 @@ bool asst::RoguelikeRecruitTaskPlugin::_run()
return false;
}
auto& char_name = selected_oper->name;
std::string char_name = selected_oper->name;
Log.trace(__FUNCTION__, "| Top priority oper:", char_name, selected_oper->priority, "page",
selected_oper->page_index, "/", i);
@@ -355,6 +371,18 @@ void asst::RoguelikeRecruitTaskPlugin::select_oper(const BattleRecruitOperInfo&
{ "level", oper.level },
};
m_status->set_str(RuntimeStatus::RoguelikeCharOverview, overview.to_string());
auto& recruit_info = RoguelikeRecruit.get_oper_info(oper.name);
if (recruit_info.name.empty() || recruit_info.is_alternate) {
return;
}
std::string teamroles_str =
m_status->get_str(RuntimeStatus::RoguelikeTeamRoles).value_or(json::value().to_string());
json::value teamroles = json::parse(teamroles_str).value_or(json::value());
std::string role_name = get_oper_role(oper.name);
int role_num = teamroles.get(role_name, 0) + 1;
teamroles[std::move(role_name)] = role_num;
m_status->set_str(RuntimeStatus::RoguelikeTeamRoles, teamroles.to_string());
}
void asst::RoguelikeRecruitTaskPlugin::swipe_to_the_left_of_operlist(int loop_times)

View File

@@ -30,6 +30,7 @@ namespace asst
private:
bool check_core_char();
std::string get_oper_role(const std::string& name);
// 招募指定干员
//
// 输入参数:

View File

@@ -20,7 +20,7 @@ bool asst::RoguelikeResetTaskPlugin::verify(AsstMsg msg, const json::value& deta
if (task_view.starts_with(roguelike_name)) {
task_view.remove_prefix(roguelike_name.length());
}
if (task_view == "Roguelike@Start") {
if (task_view == "Roguelike@StartExplore") {
return true;
}
else {

View File

@@ -95,6 +95,64 @@ namespace asst
Drone
};
inline BattleRole get_role_type(const std::string& role_name)
{
static const std::unordered_map<std::string, BattleRole> NameToRole = {
{ "warrior", BattleRole::Warrior }, { "WARRIOR", BattleRole::Warrior },
{ "Warrior", BattleRole::Warrior }, { "近卫", BattleRole::Warrior },
{ "pioneer", BattleRole::Pioneer }, { "PIONEER", BattleRole::Pioneer },
{ "Pioneer", BattleRole::Pioneer }, { "先锋", BattleRole::Pioneer },
{ "medic", BattleRole::Medic }, { "MEDIC", BattleRole::Medic },
{ "Medic", BattleRole::Medic }, { "医疗", BattleRole::Medic },
{ "tank", BattleRole::Tank }, { "TANK", BattleRole::Tank },
{ "Tank", BattleRole::Tank }, { "重装", BattleRole::Tank },
{ "sniper", BattleRole::Sniper }, { "SNIPER", BattleRole::Sniper },
{ "Sniper", BattleRole::Sniper }, { "狙击", BattleRole::Sniper },
{ "caster", BattleRole::Caster }, { "CASTER", BattleRole::Caster },
{ "Caster", BattleRole::Caster }, { "术师", BattleRole::Caster },
{ "support", BattleRole::Support }, { "SUPPORT", BattleRole::Support },
{ "Support", BattleRole::Support }, { "辅助", BattleRole::Support },
{ "special", BattleRole::Special }, { "SPECIAL", BattleRole::Special },
{ "Special", BattleRole::Special }, { "特种", BattleRole::Special },
{ "drone", BattleRole::Drone }, { "DRONE", BattleRole::Drone },
{ "Drone", BattleRole::Drone }, { "无人机", BattleRole::Drone },
};
if (auto iter = NameToRole.find(role_name); iter != NameToRole.end()) {
return iter->second;
}
return BattleRole::Unknown;
}
}
namespace std
{
inline std::string to_string(const asst::BattleRole& role)
{
static const std::unordered_map<asst::BattleRole, std::string> RoleToName = {
{ asst::BattleRole::Warrior, "Warrior" },
{ asst::BattleRole::Pioneer, "Pioneer" },
{ asst::BattleRole::Medic, "Medic" },
{ asst::BattleRole::Tank, "Tank" },
{ asst::BattleRole::Sniper, "Sniper" },
{ asst::BattleRole::Caster, "Caster" },
{ asst::BattleRole::Support, "Support" },
{ asst::BattleRole::Special, "Special" },
{ asst::BattleRole::Drone, "Drone" },
{ asst::BattleRole::Unknown, "Unknown" }
};
return RoleToName.at(role);
}
}
namespace asst {
struct BattleRealTimeOper
{
int cost = 0;