mirror of
https://github.com/MaaAssistantArknights/MaaAssistantArknights.git
synced 2026-07-05 20:30:27 +08:00
fix: 修复肉鸽关卡识别受截图速度影响的问题
This commit is contained in:
@@ -23,15 +23,20 @@
|
||||
using namespace asst::battle;
|
||||
using namespace asst::battle::roguelike;
|
||||
|
||||
asst::RoguelikeBattleTaskPlugin::RoguelikeBattleTaskPlugin(const AsstCallback& callback, Assistant* inst,
|
||||
std::string_view task_chain,
|
||||
std::shared_ptr<RoguelikeConfig> roguelike_config_ptr)
|
||||
: AbstractRoguelikeTaskPlugin(callback, inst, task_chain, roguelike_config_ptr), BattleHelper(inst)
|
||||
{}
|
||||
asst::RoguelikeBattleTaskPlugin::RoguelikeBattleTaskPlugin(
|
||||
const AsstCallback& callback,
|
||||
Assistant* inst,
|
||||
std::string_view task_chain,
|
||||
std::shared_ptr<RoguelikeConfig> roguelike_config_ptr)
|
||||
: AbstractRoguelikeTaskPlugin(callback, inst, task_chain, roguelike_config_ptr)
|
||||
, BattleHelper(inst)
|
||||
{
|
||||
}
|
||||
|
||||
bool asst::RoguelikeBattleTaskPlugin::verify(AsstMsg msg, const json::value& details) const
|
||||
{
|
||||
if (msg != AsstMsg::SubTaskCompleted || details.get("subtask", std::string()) != "ProcessTask") {
|
||||
if (msg != AsstMsg::SubTaskCompleted
|
||||
|| details.get("subtask", std::string()) != "ProcessTask") {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -101,7 +106,8 @@ void asst::RoguelikeBattleTaskPlugin::wait_until_start_button_clicked()
|
||||
.run();
|
||||
}
|
||||
|
||||
std::string asst::RoguelikeBattleTaskPlugin::oper_name_in_config(const battle::DeploymentOper& oper) const
|
||||
std::string
|
||||
asst::RoguelikeBattleTaskPlugin::oper_name_in_config(const battle::DeploymentOper& oper) const
|
||||
{
|
||||
if (oper.role == Role::Warrior && oper.name == "阿米娅") {
|
||||
return "阿米娅-WARRIOR"; // 在 BattleData.json 中有
|
||||
@@ -123,8 +129,10 @@ bool asst::RoguelikeBattleTaskPlugin::calc_stage_info()
|
||||
const auto stage_name_task_ptr = Task.get("BattleStageName");
|
||||
sleep(stage_name_task_ptr->pre_delay);
|
||||
|
||||
constexpr int StageNameRetryTimes = 100;
|
||||
for (int i = 0; i != StageNameRetryTimes; ++i) {
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
constexpr auto kTimeout = std::chrono::seconds(20);
|
||||
|
||||
while (std::chrono::steady_clock::now() - start < kTimeout) {
|
||||
if (need_exit()) {
|
||||
return false;
|
||||
}
|
||||
@@ -138,7 +146,10 @@ bool asst::RoguelikeBattleTaskPlugin::calc_stage_info()
|
||||
continue;
|
||||
}
|
||||
|
||||
static const std::vector<std::string> RoguelikeStageCode = { "ISW-NO", "ISW-DF", "ISW-DU", "ISW-SP",
|
||||
static const std::vector<std::string> RoguelikeStageCode = { "ISW-NO",
|
||||
"ISW-DF",
|
||||
"ISW-DU",
|
||||
"ISW-SP",
|
||||
std::string() };
|
||||
TilePack::LevelKey stage_key;
|
||||
stage_key.name = text;
|
||||
@@ -176,9 +187,10 @@ bool asst::RoguelikeBattleTaskPlugin::calc_stage_info()
|
||||
m_blacklist_location = opt->blacklist_location;
|
||||
m_role_order = opt->role_order;
|
||||
m_force_deploy_direction = opt->force_deploy_direction;
|
||||
m_force_air_defense = AirDefenseData { .stop_blocking_deploy_num = opt->stop_deploy_blocking_num,
|
||||
.deploy_air_defense_num = opt->force_deploy_air_defense_num,
|
||||
.ban_medic = opt->force_ban_medic };
|
||||
m_force_air_defense =
|
||||
AirDefenseData { .stop_blocking_deploy_num = opt->stop_deploy_blocking_num,
|
||||
.deploy_air_defense_num = opt->force_deploy_air_defense_num,
|
||||
.ban_medic = opt->force_ban_medic };
|
||||
m_deploy_plan = opt->deploy_plan;
|
||||
m_retreat_plan = opt->retreat_plan;
|
||||
}
|
||||
@@ -197,9 +209,10 @@ bool asst::RoguelikeBattleTaskPlugin::calc_stage_info()
|
||||
}
|
||||
else {
|
||||
auto homes_pos = m_homes | views::transform(&ReplacementHome::location);
|
||||
auto invalid_homes_pos =
|
||||
homes_pos | views::filter([&](const auto& home_pos) { return !m_normal_tile_info.contains(home_pos); }) |
|
||||
views::transform(&Point::to_string);
|
||||
auto invalid_homes_pos = homes_pos | views::filter([&](const auto& home_pos) {
|
||||
return !m_normal_tile_info.contains(home_pos);
|
||||
})
|
||||
| views::transform(&Point::to_string);
|
||||
if (!invalid_homes_pos.empty()) {
|
||||
Log.error("No replacement homes point:", invalid_homes_pos);
|
||||
}
|
||||
@@ -227,7 +240,8 @@ asst::battle::LocationType asst::RoguelikeBattleTaskPlugin::get_oper_location_ty
|
||||
return BattleData.get_location_type(oper_name_in_config(oper));
|
||||
}
|
||||
|
||||
asst::battle::OperPosition asst::RoguelikeBattleTaskPlugin::get_role_position(const battle::Role& role) const
|
||||
asst::battle::OperPosition
|
||||
asst::RoguelikeBattleTaskPlugin::get_role_position(const battle::Role& role) const
|
||||
{
|
||||
switch (role) {
|
||||
case battle::Role::Support:
|
||||
@@ -241,7 +255,8 @@ asst::battle::OperPosition asst::RoguelikeBattleTaskPlugin::get_role_position(co
|
||||
return battle::OperPosition::Blocking;
|
||||
break;
|
||||
case battle::Role::Medic:
|
||||
return m_force_air_defense.ban_medic ? battle::OperPosition::None : battle::OperPosition::AirDefense;
|
||||
return m_force_air_defense.ban_medic ? battle::OperPosition::None
|
||||
: battle::OperPosition::AirDefense;
|
||||
break;
|
||||
case battle::Role::Special:
|
||||
case battle::Role::Drone:
|
||||
@@ -255,7 +270,9 @@ void asst::RoguelikeBattleTaskPlugin::cache_oper_elite_status()
|
||||
{
|
||||
const auto& oper_list = m_config->get_oper();
|
||||
for (const auto& oper : m_cur_deployment_opers) {
|
||||
m_oper_elite.emplace(oper.name, oper_list.contains(oper.name) ? oper_list.at(oper.name).elite : 0);
|
||||
m_oper_elite.emplace(
|
||||
oper.name,
|
||||
oper_list.contains(oper.name) ? oper_list.at(oper.name).elite : 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +303,9 @@ void asst::RoguelikeBattleTaskPlugin::set_position_full(const Point& loc, bool f
|
||||
}
|
||||
}
|
||||
|
||||
void asst::RoguelikeBattleTaskPlugin::set_position_full(const battle::DeploymentOper& oper, bool full)
|
||||
void asst::RoguelikeBattleTaskPlugin::set_position_full(
|
||||
const battle::DeploymentOper& oper,
|
||||
bool full)
|
||||
{
|
||||
set_position_full(get_oper_location_type(oper), full);
|
||||
}
|
||||
@@ -349,7 +368,8 @@ bool asst::RoguelikeBattleTaskPlugin::do_best_deploy()
|
||||
// 获取招募信息
|
||||
const auto& recruit_info = RoguelikeRecruit.get_oper_info(m_config->get_theme(), oper_name);
|
||||
// 获取会用到该干员的干员组[干员组1序号,干员组2序号,...]
|
||||
std::vector<int> group_ids = RoguelikeRecruit.get_group_id(m_config->get_theme(), oper_name);
|
||||
std::vector<int> group_ids =
|
||||
RoguelikeRecruit.get_group_id(m_config->get_theme(), oper_name);
|
||||
|
||||
for (const auto& group_id : group_ids) {
|
||||
// 当前干员组名,string类型
|
||||
@@ -358,7 +378,12 @@ bool asst::RoguelikeBattleTaskPlugin::do_best_deploy()
|
||||
if (m_deploy_plan.contains(group_name)) {
|
||||
for (const auto& info : m_deploy_plan[group_name]) {
|
||||
if (m_kills < info.kill_lower_bound || m_kills > info.kill_upper_bound) {
|
||||
Log.debug(" deploy info", oper.name, "in group", group_name, "is waiting.");
|
||||
Log.debug(
|
||||
" deploy info",
|
||||
oper.name,
|
||||
"in group",
|
||||
group_name,
|
||||
"is waiting.");
|
||||
is_success = true; // 如果发现了待命干员,此函数最终返回true
|
||||
continue;
|
||||
}
|
||||
@@ -369,13 +394,22 @@ bool asst::RoguelikeBattleTaskPlugin::do_best_deploy()
|
||||
// deploy_plan.oper_order_in_group = recruit_info.order_in_group.at(group_id);
|
||||
|
||||
deploy_plan.oper_order_in_group =
|
||||
recruit_info.order_in_group.empty() ? INT_MAX : recruit_info.order_in_group.at(group_id);
|
||||
recruit_info.order_in_group.empty()
|
||||
? INT_MAX
|
||||
: recruit_info.order_in_group.at(group_id);
|
||||
deploy_plan.rank = info.rank;
|
||||
deploy_plan.placed = info.location;
|
||||
deploy_plan.direction = info.direction;
|
||||
deploy_plan_list.emplace_back(deploy_plan);
|
||||
Log.debug(" deploy info", deploy_plan.oper_name, "is No. ", deploy_plan.oper_order_in_group + 1,
|
||||
"in group", group_name, ", with deploy command rank", deploy_plan.rank);
|
||||
Log.debug(
|
||||
" deploy info",
|
||||
deploy_plan.oper_name,
|
||||
"is No. ",
|
||||
deploy_plan.oper_order_in_group + 1,
|
||||
"in group",
|
||||
group_name,
|
||||
", with deploy command rank",
|
||||
deploy_plan.rank);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -385,14 +419,18 @@ bool asst::RoguelikeBattleTaskPlugin::do_best_deploy()
|
||||
}
|
||||
std::sort(deploy_plan_list.begin(), deploy_plan_list.end());
|
||||
for (const auto& deploy_plan : deploy_plan_list) {
|
||||
if (!m_used_tiles.contains(deploy_plan.placed) &&
|
||||
!m_blacklist_location.contains(deploy_plan.placed) /* 判断该位置是否已被占据 */) {
|
||||
|
||||
if (auto oper_it = ranges::find_if(m_cur_deployment_opers,
|
||||
[&](const auto& oper) { return oper.name == deploy_plan.oper_name; });
|
||||
if (!m_used_tiles.contains(deploy_plan.placed)
|
||||
&& !m_blacklist_location.contains(deploy_plan.placed) /* 判断该位置是否已被占据 */) {
|
||||
if (auto oper_it = ranges::find_if(
|
||||
m_cur_deployment_opers,
|
||||
[&](const auto& oper) { return oper.name == deploy_plan.oper_name; });
|
||||
oper_it == m_cur_deployment_opers.end() || !oper_it->available) { // 等费
|
||||
Log.trace(" best deploy is", deploy_plan.oper_name, "with rank", deploy_plan.rank,
|
||||
"but now waiting for cost.");
|
||||
Log.trace(
|
||||
" best deploy is",
|
||||
deploy_plan.oper_name,
|
||||
"with rank",
|
||||
deploy_plan.rank,
|
||||
"but now waiting for cost.");
|
||||
return true;
|
||||
}
|
||||
deploy_oper(deploy_plan.oper_name, deploy_plan.placed, deploy_plan.direction);
|
||||
@@ -400,7 +438,8 @@ bool asst::RoguelikeBattleTaskPlugin::do_best_deploy()
|
||||
auto deployed_time = std::chrono::steady_clock::now();
|
||||
m_deployed_time.insert_or_assign(deploy_plan.oper_name, deployed_time);
|
||||
// 获取技能用法和使用次数
|
||||
const auto& oper_info = RoguelikeRecruit.get_oper_info(m_config->get_theme(), deploy_plan.oper_name);
|
||||
const auto& oper_info =
|
||||
RoguelikeRecruit.get_oper_info(m_config->get_theme(), deploy_plan.oper_name);
|
||||
m_skill_usage[deploy_plan.oper_name] = oper_info.skill_usage;
|
||||
m_skill_times[deploy_plan.oper_name] = oper_info.skill_times;
|
||||
Log.trace(" best deploy is", deploy_plan.oper_name, "with rank", deploy_plan.rank);
|
||||
@@ -432,8 +471,8 @@ bool asst::RoguelikeBattleTaskPlugin::do_once()
|
||||
const auto& oper_info = RoguelikeRecruit.get_oper_info(m_config->get_theme(), name);
|
||||
auto iter = m_deployed_time.find(name);
|
||||
if (iter != m_deployed_time.end() && oper_info.auto_retreat > 0) {
|
||||
if (std::chrono::steady_clock::now() - m_deployed_time.at(name) >=
|
||||
oper_info.auto_retreat * std::chrono::seconds(1)) {
|
||||
if (std::chrono::steady_clock::now() - m_deployed_time.at(name)
|
||||
>= oper_info.auto_retreat * std::chrono::seconds(1)) {
|
||||
// 时间到了就撤退
|
||||
asst::BattleHelper::retreat_oper(name);
|
||||
m_deployed_time.erase(name);
|
||||
@@ -452,14 +491,18 @@ bool asst::RoguelikeBattleTaskPlugin::do_once()
|
||||
size_t cur_available_count = 0; // without drones
|
||||
size_t cur_deployments_count = 0; // without drones
|
||||
for (const auto& oper : m_cur_deployment_opers) {
|
||||
if (oper.role == Role::Drone) continue;
|
||||
if (oper.role == Role::Drone) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++cur_deployments_count;
|
||||
if (oper.cooling) {
|
||||
cur_cooling.emplace(oper.name);
|
||||
m_deployed_time.erase(oper.name);
|
||||
}
|
||||
if (oper.available) ++cur_available_count;
|
||||
if (oper.available) {
|
||||
++cur_available_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (do_best_deploy()) { // 这是新的部署逻辑,更加精确
|
||||
@@ -489,8 +532,9 @@ bool asst::RoguelikeBattleTaskPlugin::do_once()
|
||||
m_cur_home_index = *urgent_home_opt;
|
||||
|
||||
if (m_allow_to_use_dice) {
|
||||
auto dice_key_iter = ranges::find_if(m_cur_deployment_opers,
|
||||
[&](const auto& oper) { return DiceSet.contains(oper.name); });
|
||||
auto dice_key_iter = ranges::find_if(m_cur_deployment_opers, [&](const auto& oper) {
|
||||
return DiceSet.contains(oper.name);
|
||||
});
|
||||
if (dice_key_iter != m_cur_deployment_opers.end()) {
|
||||
best_oper_is_dice = true;
|
||||
best_oper = *dice_key_iter;
|
||||
@@ -526,7 +570,8 @@ bool asst::RoguelikeBattleTaskPlugin::do_once()
|
||||
auto deployed_time = std::chrono::steady_clock::now();
|
||||
m_deployed_time.insert_or_assign(best_oper.name, deployed_time);
|
||||
// 获取技能用法和使用次数
|
||||
const auto& oper_info = RoguelikeRecruit.get_oper_info(m_config->get_theme(), best_oper.name);
|
||||
const auto& oper_info =
|
||||
RoguelikeRecruit.get_oper_info(m_config->get_theme(), best_oper.name);
|
||||
m_skill_usage[best_oper.name] = oper_info.skill_usage;
|
||||
m_skill_times[best_oper.name] = oper_info.skill_times;
|
||||
|
||||
@@ -543,16 +588,18 @@ bool asst::RoguelikeBattleTaskPlugin::do_once()
|
||||
return true;
|
||||
}
|
||||
|
||||
void asst::RoguelikeBattleTaskPlugin::postproc_of_deployment_conditions(const battle::DeploymentOper& oper,
|
||||
const Point& placed_loc,
|
||||
battle::DeployDirection direction)
|
||||
void asst::RoguelikeBattleTaskPlugin::postproc_of_deployment_conditions(
|
||||
const battle::DeploymentOper& oper,
|
||||
const Point& placed_loc,
|
||||
battle::DeployDirection direction)
|
||||
{
|
||||
// 如果是医疗干员,判断覆盖范围内有无第一次放置的干员
|
||||
if (oper.role == battle::Role::Medic) {
|
||||
std::vector<size_t> contain_index;
|
||||
for (const Point& relative_pos : get_attack_range(oper, direction)) {
|
||||
Point absolute_pos = placed_loc + relative_pos;
|
||||
if (auto iter = m_blocking_for_home_index.find(absolute_pos); iter != m_blocking_for_home_index.end()) {
|
||||
if (auto iter = m_blocking_for_home_index.find(absolute_pos);
|
||||
iter != m_blocking_for_home_index.end()) {
|
||||
m_homes_status[iter->second].wait_medic = false;
|
||||
contain_index.emplace_back(iter->second);
|
||||
}
|
||||
@@ -577,7 +624,8 @@ void asst::RoguelikeBattleTaskPlugin::postproc_of_deployment_conditions(const ba
|
||||
case OperPosition::AirDefense:
|
||||
if (!m_force_air_defense.has_finished_deploy_air_defense) {
|
||||
m_force_air_defense.has_deployed_air_defense_num++;
|
||||
if (m_force_air_defense.has_deployed_air_defense_num >= m_force_air_defense.deploy_air_defense_num) {
|
||||
if (m_force_air_defense.has_deployed_air_defense_num
|
||||
>= m_force_air_defense.deploy_air_defense_num) {
|
||||
m_force_air_defense.has_finished_deploy_air_defense = true;
|
||||
Log.info("FORCE RANGED OPER DEPLOY END");
|
||||
}
|
||||
@@ -587,7 +635,8 @@ void asst::RoguelikeBattleTaskPlugin::postproc_of_deployment_conditions(const ba
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_force_air_defense.has_finished_deploy_air_defense && position != OperPosition::AirDefense) {
|
||||
if (m_force_air_defense.has_finished_deploy_air_defense
|
||||
&& position != OperPosition::AirDefense) {
|
||||
Log.info("FORCE RANGED OPER DEPLOY END");
|
||||
m_force_air_defense.has_finished_deploy_air_defense = true;
|
||||
}
|
||||
@@ -600,7 +649,12 @@ void asst::RoguelikeBattleTaskPlugin::check_drone_tiles()
|
||||
while ((!m_need_clear_tiles.empty()) && m_need_clear_tiles.top().placed_time < now_time) {
|
||||
const auto& placed_loc = m_need_clear_tiles.top().placed_loc;
|
||||
if (auto iter = m_used_tiles.find(placed_loc); iter != m_used_tiles.end()) {
|
||||
Log.info("Drone at location (", placed_loc.x, ",", placed_loc.y, ") is recognized as retreated");
|
||||
Log.info(
|
||||
"Drone at location (",
|
||||
placed_loc.x,
|
||||
",",
|
||||
placed_loc.y,
|
||||
") is recognized as retreated");
|
||||
set_position_full(placed_loc, false);
|
||||
m_battlefield_opers.erase(iter->second);
|
||||
m_used_tiles.erase(iter);
|
||||
@@ -609,9 +663,10 @@ void asst::RoguelikeBattleTaskPlugin::check_drone_tiles()
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<size_t> asst::RoguelikeBattleTaskPlugin::check_urgent(const std::unordered_set<std::string>& pre_cooling,
|
||||
const std::unordered_set<std::string>& cur_cooling,
|
||||
const std::map<std::string, Point>& pre_battlefield)
|
||||
std::optional<size_t> asst::RoguelikeBattleTaskPlugin::check_urgent(
|
||||
const std::unordered_set<std::string>& pre_cooling,
|
||||
const std::unordered_set<std::string>& cur_cooling,
|
||||
const std::map<std::string, Point>& pre_battlefield)
|
||||
{
|
||||
std::vector<size_t> new_urgent;
|
||||
for (const auto& name : cur_cooling) {
|
||||
@@ -693,19 +748,31 @@ std::optional<asst::battle::DeploymentOper> asst::RoguelikeBattleTaskPlugin::cal
|
||||
}
|
||||
}
|
||||
|
||||
bool use_air_defense =
|
||||
has_air_defense && !m_force_air_defense.has_finished_deploy_air_defense &&
|
||||
m_force_air_defense.has_deployed_blocking_num >= m_force_air_defense.stop_blocking_deploy_num && !m_ranged_full;
|
||||
bool use_blocking = has_blocking && m_homes_status[m_cur_home_index].wait_blocking && !m_melee_full;
|
||||
bool use_air_defense = has_air_defense && !m_force_air_defense.has_finished_deploy_air_defense
|
||||
&& m_force_air_defense.has_deployed_blocking_num
|
||||
>= m_force_air_defense.stop_blocking_deploy_num
|
||||
&& !m_ranged_full;
|
||||
bool use_blocking =
|
||||
has_blocking && m_homes_status[m_cur_home_index].wait_blocking && !m_melee_full;
|
||||
bool use_medic = has_medic && m_homes_status[m_cur_home_index].wait_medic && !m_ranged_full;
|
||||
Log.trace("use_air_defense", use_air_defense, ", use_blocking", use_blocking, ", use_medic", use_medic);
|
||||
Log.trace(
|
||||
"use_air_defense",
|
||||
use_air_defense,
|
||||
", use_blocking",
|
||||
use_blocking,
|
||||
", use_medic",
|
||||
use_medic);
|
||||
|
||||
std::vector<DeploymentOper> cur_available;
|
||||
for (const auto& oper : m_cur_deployment_opers) {
|
||||
if (oper.available) cur_available.emplace_back(oper);
|
||||
if (oper.available) {
|
||||
cur_available.emplace_back(oper);
|
||||
}
|
||||
}
|
||||
// 费用高的优先用,放前面
|
||||
ranges::sort(cur_available, [](const auto& lhs, const auto& rhs) { return lhs.cost > rhs.cost; });
|
||||
ranges::sort(cur_available, [](const auto& lhs, const auto& rhs) {
|
||||
return lhs.cost > rhs.cost;
|
||||
});
|
||||
|
||||
DeploymentOper best_oper;
|
||||
|
||||
@@ -787,7 +854,8 @@ void asst::RoguelikeBattleTaskPlugin::clear()
|
||||
m_oper_elite.clear();
|
||||
}
|
||||
|
||||
std::vector<asst::Point> asst::RoguelikeBattleTaskPlugin::available_locations(const DeploymentOper& oper) const
|
||||
std::vector<asst::Point>
|
||||
asst::RoguelikeBattleTaskPlugin::available_locations(const DeploymentOper& oper) const
|
||||
{
|
||||
auto type = get_oper_location_type(oper);
|
||||
if (type == LocationType::Invalid || type == LocationType::None) {
|
||||
@@ -796,15 +864,18 @@ std::vector<asst::Point> asst::RoguelikeBattleTaskPlugin::available_locations(co
|
||||
return available_locations(type);
|
||||
}
|
||||
|
||||
std::vector<asst::Point> asst::RoguelikeBattleTaskPlugin::available_locations(battle::LocationType type) const
|
||||
std::vector<asst::Point>
|
||||
asst::RoguelikeBattleTaskPlugin::available_locations(battle::LocationType type) const
|
||||
{
|
||||
std::vector<Point> result;
|
||||
for (const auto& [loc, tile] : m_normal_tile_info) {
|
||||
bool position_matched = tile.buildable == type || tile.buildable == battle::LocationType::All;
|
||||
position_matched |= (type == battle::LocationType::All) && (tile.buildable == battle::LocationType::Melee ||
|
||||
tile.buildable == battle::LocationType::Ranged);
|
||||
if (position_matched &&
|
||||
tile.key != TilePack::TileKey::DeepSea && // 水上要先放板子才能放人,肉鸽里也没板子,那就当作不可放置
|
||||
bool position_matched =
|
||||
tile.buildable == type || tile.buildable == battle::LocationType::All;
|
||||
position_matched |= (type == battle::LocationType::All)
|
||||
&& (tile.buildable == battle::LocationType::Melee
|
||||
|| tile.buildable == battle::LocationType::Ranged);
|
||||
if (position_matched && tile.key != TilePack::TileKey::DeepSea
|
||||
&& // 水上要先放板子才能放人,肉鸽里也没板子,那就当作不可放置
|
||||
!m_used_tiles.contains(loc) && !m_blacklist_location.contains(loc)) {
|
||||
result.emplace_back(loc);
|
||||
}
|
||||
@@ -812,8 +883,9 @@ std::vector<asst::Point> asst::RoguelikeBattleTaskPlugin::available_locations(ba
|
||||
return result;
|
||||
}
|
||||
|
||||
asst::battle::AttackRange asst::RoguelikeBattleTaskPlugin::get_attack_range(const battle::DeploymentOper& oper,
|
||||
DeployDirection direction) const
|
||||
asst::battle::AttackRange asst::RoguelikeBattleTaskPlugin::get_attack_range(
|
||||
const battle::DeploymentOper& oper,
|
||||
DeployDirection direction) const
|
||||
{
|
||||
int64_t elite = 0;
|
||||
if (m_oper_elite.contains(oper.name)) {
|
||||
@@ -859,20 +931,25 @@ asst::battle::AttackRange asst::RoguelikeBattleTaskPlugin::get_attack_range(cons
|
||||
}
|
||||
}
|
||||
|
||||
for (auto cur_direction :
|
||||
{ DeployDirection::Right, DeployDirection::Up, DeployDirection::Left, DeployDirection::Down }) {
|
||||
if (cur_direction == direction) break;
|
||||
for (auto cur_direction : { DeployDirection::Right,
|
||||
DeployDirection::Up,
|
||||
DeployDirection::Left,
|
||||
DeployDirection::Down }) {
|
||||
if (cur_direction == direction) {
|
||||
break;
|
||||
}
|
||||
|
||||
// rotate relative attack range counterclockwise
|
||||
for (Point& point : right_attack_range)
|
||||
for (Point& point : right_attack_range) {
|
||||
point = { point.y, -point.x };
|
||||
}
|
||||
}
|
||||
|
||||
return right_attack_range;
|
||||
}
|
||||
|
||||
std::optional<asst::RoguelikeBattleTaskPlugin::DeployInfo> asst::RoguelikeBattleTaskPlugin::calc_best_loc(
|
||||
const battle::DeploymentOper& oper) const
|
||||
std::optional<asst::RoguelikeBattleTaskPlugin::DeployInfo>
|
||||
asst::RoguelikeBattleTaskPlugin::calc_best_loc(const battle::DeploymentOper& oper) const
|
||||
{
|
||||
size_t home_index = m_cur_home_index;
|
||||
if (home_index >= m_homes.size()) {
|
||||
@@ -911,10 +988,12 @@ std::optional<asst::RoguelikeBattleTaskPlugin::DeployInfo> asst::RoguelikeBattle
|
||||
// 取距离最近的N个点,计算分数。然后使用得分最高的点
|
||||
constexpr int CalcPointCount = 4;
|
||||
for (const auto& loc : available_loc | views::take(CalcPointCount)) {
|
||||
const auto& [cur_direction, cur_socre] = calc_best_direction_and_score(loc, oper, home.direction);
|
||||
const auto& [cur_direction, cur_socre] =
|
||||
calc_best_direction_and_score(loc, oper, home.direction);
|
||||
// 离得远的要扣分
|
||||
constexpr int DistWeights = -1050;
|
||||
int extra_dist = std::abs(loc.x - home.location.x) + std::abs(loc.y - home.location.y) - min_dist;
|
||||
int extra_dist =
|
||||
std::abs(loc.x - home.location.x) + std::abs(loc.y - home.location.y) - min_dist;
|
||||
int extra_dist_score = DistWeights * extra_dist;
|
||||
if (oper.role == battle::Role::Medic) { // 医疗干员离得远无所谓
|
||||
extra_dist_score = 0;
|
||||
@@ -928,7 +1007,8 @@ std::optional<asst::RoguelikeBattleTaskPlugin::DeployInfo> asst::RoguelikeBattle
|
||||
}
|
||||
|
||||
// 强制变化为确定的攻击方向
|
||||
if (auto iter = m_force_deploy_direction.find(best_location); iter != m_force_deploy_direction.end()) {
|
||||
if (auto iter = m_force_deploy_direction.find(best_location);
|
||||
iter != m_force_deploy_direction.end()) {
|
||||
if (iter->second.role.contains(oper.role)) {
|
||||
best_direction = iter->second.direction;
|
||||
}
|
||||
@@ -937,8 +1017,11 @@ std::optional<asst::RoguelikeBattleTaskPlugin::DeployInfo> asst::RoguelikeBattle
|
||||
return DeployInfo { best_location, best_direction };
|
||||
}
|
||||
|
||||
asst::RoguelikeBattleTaskPlugin::DirectionAndScore asst::RoguelikeBattleTaskPlugin::calc_best_direction_and_score(
|
||||
Point loc, const battle::DeploymentOper& oper, DeployDirection recommended_direction) const
|
||||
asst::RoguelikeBattleTaskPlugin::DirectionAndScore
|
||||
asst::RoguelikeBattleTaskPlugin::calc_best_direction_and_score(
|
||||
Point loc,
|
||||
const battle::DeploymentOper& oper,
|
||||
DeployDirection recommended_direction) const
|
||||
{
|
||||
LogTraceFunction;
|
||||
|
||||
@@ -994,8 +1077,10 @@ asst::RoguelikeBattleTaskPlugin::DirectionAndScore asst::RoguelikeBattleTaskPlug
|
||||
int max_score = 0;
|
||||
DeployDirection best_direction = DeployDirection::None;
|
||||
|
||||
for (auto direction :
|
||||
{ DeployDirection::Right, DeployDirection::Up, DeployDirection::Left, DeployDirection::Down }) {
|
||||
for (auto direction : { DeployDirection::Right,
|
||||
DeployDirection::Up,
|
||||
DeployDirection::Left,
|
||||
DeployDirection::Down }) {
|
||||
int score = 0;
|
||||
// 按朝右算,后面根据方向做转换
|
||||
for (const Point& relative_pos : get_attack_range(oper, direction)) {
|
||||
@@ -1004,12 +1089,14 @@ asst::RoguelikeBattleTaskPlugin::DirectionAndScore asst::RoguelikeBattleTaskPlug
|
||||
using TileKey = TilePack::TileKey;
|
||||
// 战斗干员朝向的权重
|
||||
static const std::unordered_map<TileKey, int> TileKeyFightWeights = {
|
||||
{ TileKey::Invalid, 0 }, { TileKey::Forbidden, 0 }, { TileKey::Wall, 500 },
|
||||
{ TileKey::Road, 1000 }, { TileKey::Home, 500 }, { TileKey::EnemyHome, 1000 },
|
||||
{ TileKey::Airport, 1000 }, { TileKey::Floor, 1000 }, { TileKey::Hole, 0 },
|
||||
{ TileKey::Telin, 700 }, { TileKey::Telout, 800 }, { TileKey::Grass, 500 },
|
||||
{ TileKey::DeepSea, 1000 }, { TileKey::Volcano, 1000 }, { TileKey::Healing, 1000 },
|
||||
{ TileKey::Fence, 800 },
|
||||
{ TileKey::Invalid, 0 }, { TileKey::Forbidden, 0 },
|
||||
{ TileKey::Wall, 500 }, { TileKey::Road, 1000 },
|
||||
{ TileKey::Home, 500 }, { TileKey::EnemyHome, 1000 },
|
||||
{ TileKey::Airport, 1000 }, { TileKey::Floor, 1000 },
|
||||
{ TileKey::Hole, 0 }, { TileKey::Telin, 700 },
|
||||
{ TileKey::Telout, 800 }, { TileKey::Grass, 500 },
|
||||
{ TileKey::DeepSea, 1000 }, { TileKey::Volcano, 1000 },
|
||||
{ TileKey::Healing, 1000 }, { TileKey::Fence, 800 },
|
||||
};
|
||||
// 治疗干员朝向的权重
|
||||
static const std::unordered_map<TileKey, int> TileKeyMedicWeights = {
|
||||
@@ -1024,15 +1111,21 @@ asst::RoguelikeBattleTaskPlugin::DirectionAndScore asst::RoguelikeBattleTaskPlug
|
||||
switch (oper.role) {
|
||||
case battle::Role::Medic:
|
||||
if (auto iter = m_used_tiles.find(absolute_pos);
|
||||
iter != m_used_tiles.cend() &&
|
||||
BattleData.get_role(iter->second) != battle::Role::Drone) // 根据哪个方向上人多决定朝向哪
|
||||
iter != m_used_tiles.cend()
|
||||
&& BattleData.get_role(iter->second)
|
||||
!= battle::Role::Drone) { // 根据哪个方向上人多决定朝向哪
|
||||
score += 10000;
|
||||
if (auto iter = m_side_tile_info.find(absolute_pos); iter != m_side_tile_info.end())
|
||||
}
|
||||
if (auto iter = m_side_tile_info.find(absolute_pos);
|
||||
iter != m_side_tile_info.end()) {
|
||||
score += TileKeyMedicWeights.at(iter->second.key);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (auto iter = m_side_tile_info.find(absolute_pos); iter != m_side_tile_info.end())
|
||||
if (auto iter = m_side_tile_info.find(absolute_pos);
|
||||
iter != m_side_tile_info.end()) {
|
||||
score += TileKeyFightWeights.at(iter->second.key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user