Merge pull request #4588 from mattsc/various_ai_features
Implement various AI feature requests and fixes
This commit is contained in:
commit
a7aa08c90a
18 changed files with 322 additions and 81 deletions
|
@ -1062,6 +1062,18 @@ end
|
|||
|
||||
--------- Unit related helper functions ----------
|
||||
|
||||
function ai_helper.is_passive_leader(aspect_value, id)
|
||||
if (type(aspect_value) == 'boolean') then return aspect_value end
|
||||
|
||||
for _,aspect_id in ipairs(aspect_value) do
|
||||
if (aspect_id == id) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ai_helper.get_live_units(filter)
|
||||
-- Note: the order of the filters and the [and] tags are important for speed reasons
|
||||
return wesnoth.units.find_on_map { { "not", { status = "petrified" } }, { "and", filter } }
|
||||
|
|
|
@ -84,7 +84,15 @@ function ca_castle_switch:evaluation(cfg, data, filter_own, recruiting_leader)
|
|||
}, true)
|
||||
end
|
||||
|
||||
if (not leaders[1]) then
|
||||
local leader
|
||||
for _,l in pairs(leaders) do
|
||||
if (not AH.is_passive_leader(ai.aspects.passive_leader, l.id)) then
|
||||
leader = l
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not leader then
|
||||
-- CA is irrelevant if no leader or the leader may have moved from another CA
|
||||
data.CS_leader, data.CS_leader_target = nil, nil
|
||||
if AH.print_eval() then AH.done_eval_messages(start_time, ca_name) end
|
||||
|
@ -237,7 +245,7 @@ end
|
|||
|
||||
function ca_castle_switch:execution(cfg, data, filter_own)
|
||||
if AH.print_exec() then AH.print_ts(' Executing castle_switch CA') end
|
||||
if AH.show_messages() then wesnoth.wml_actions.message { speaker = leader.id, message = 'Switching castles' } end
|
||||
if AH.show_messages() then wesnoth.wml_actions.message { speaker = data.leader.id, message = 'Switching castles' } end
|
||||
|
||||
AH.robust_move_and_attack(ai, data.CS_leader, data.CS_leader_target, nil, { partial_move = true })
|
||||
data.CS_leader, data.CS_leader_target = nil
|
||||
|
|
|
@ -54,7 +54,12 @@ function ca_attack_highxp:evaluation(cfg, data, filter_own)
|
|||
-- but it is much faster than path finding, so it is done for preselection.
|
||||
local target_infos = {}
|
||||
for i_t,enemy in ipairs(attacks_aspect.enemy) do
|
||||
if AH.is_attackable_enemy(enemy) then
|
||||
local enemy_can_advance = true
|
||||
if (not enemy.advances_to[1]) and (not wml.get_child(enemy.__cfg, 'advancement')) then
|
||||
enemy_can_advance = false
|
||||
end
|
||||
|
||||
if enemy_can_advance and AH.is_attackable_enemy(enemy) then
|
||||
local XP_to_levelup = enemy.max_experience - enemy.experience
|
||||
if (max_unit_level * wesnoth.game_config.combat_experience >= XP_to_levelup) then
|
||||
local potential_target = false
|
||||
|
|
|
@ -18,14 +18,15 @@ local params = { score_function = (function() return 196000 end) }
|
|||
if ca_castle_switch then
|
||||
params.min_turn_1_recruit = (function() return ca_castle_switch:evaluation({}, dummy_engine.data) > 0 end)
|
||||
params.leader_takes_village = (function(leader)
|
||||
if ca_castle_switch:evaluation({}, dummy_engine.data, nil, leader) > 0 then
|
||||
local castle_switch_score = ca_castle_switch:evaluation({}, dummy_engine.data, nil, leader)
|
||||
if castle_switch_score > 0 then
|
||||
local take_village = #(wesnoth.get_villages {
|
||||
x = dummy_engine.data.CS_leader_target[1],
|
||||
y = dummy_engine.data.CS_leader_target[2]
|
||||
}) > 0
|
||||
return take_village
|
||||
return castle_switch_score, take_village
|
||||
end
|
||||
return not ai.aspects.passive_leader
|
||||
return 0
|
||||
end
|
||||
)
|
||||
end
|
||||
|
@ -45,4 +46,4 @@ function ca_recruit_rushers:execution(cfg, data)
|
|||
return dummy_engine:recruit_rushers_exec()
|
||||
end
|
||||
|
||||
return ca_recruit_rushers
|
||||
return ca_recruit_rushers
|
||||
|
|
|
@ -12,8 +12,9 @@ return {
|
|||
-- (default = 0.1)
|
||||
-- min_turn_1_recruit: function that returns true if only enough units to grab nearby villages should be recruited turn 1, false otherwise
|
||||
-- (default always returns false)
|
||||
-- leader_takes_village: function that returns true if and only if the leader is going to move to capture a village this turn
|
||||
-- (default returns 'not ai.aspects.passive_leader')
|
||||
-- leader_takes_village: function that returns the score of the castle_switch CA as its first parameter.
|
||||
-- If this score is greater than zero, the second parameter is a boolean indicating whether the
|
||||
-- castle switch move will make the leader end up on a village.
|
||||
-- enemy_types: array of default enemy unit types to consider if there are no enemies on the map
|
||||
-- and no enemy sides exist or have recruit lists
|
||||
-- Note: the recruiting code assumes full knowledge of units on the map and the recruit lists of other sides for the purpose of
|
||||
|
@ -928,7 +929,18 @@ return {
|
|||
data.castle.assigned_villages_x = {}
|
||||
data.castle.assigned_villages_y = {}
|
||||
|
||||
if not ai.aspects.passive_leader and (not params.leader_takes_village or params.leader_takes_village(leader)) then
|
||||
-- If castle_switch CA makes the unit end up on a village, skip one village for the leader.
|
||||
-- Also do so if the leader is not passive. Note that the castle_switch CA will also return zero
|
||||
-- when the leader is passive, but not only in that case.
|
||||
local ltv_score, skip_one_village = 0
|
||||
if params.leader_takes_village then
|
||||
ltv_score, skip_one_village = params.leader_takes_village(leader)
|
||||
end
|
||||
if (ltv_score == 0) then
|
||||
skip_one_village = not AH.is_passive_leader(ai.aspects.passive_leader, leader.id)
|
||||
end
|
||||
|
||||
if skip_one_village then
|
||||
-- skip one village for the leader
|
||||
for i,v in ipairs(villages) do
|
||||
local path, cost = wesnoth.find_path(leader, v[1], v[2], {max_cost = leader.max_moves+1})
|
||||
|
|
|
@ -423,7 +423,7 @@ void move_result::do_check_after()
|
|||
}
|
||||
|
||||
if (!unreach_is_ok_ && unit_location_!=to_) {
|
||||
set_error(E_NOT_REACHED_DESTINATION);
|
||||
DBG_AI_ACTIONS << "Unit did not reach destination in " << do_describe(); //Demotes to DBG "not reached destination" warning
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1086,7 +1086,6 @@ const std::string& actions::get_error_name(int error_code)
|
|||
error_names_.emplace(move_result::E_INCAPACITATED_UNIT, "move_result::E_INCAPACITATED_UNIT");
|
||||
error_names_.emplace(move_result::E_AMBUSHED, "move_result::E_AMBUSHED");
|
||||
error_names_.emplace(move_result::E_FAILED_TELEPORT, "move_result::E_FAILED_TELEPORT");
|
||||
error_names_.emplace(move_result::E_NOT_REACHED_DESTINATION, "move_result::E_NOT_REACHED_DESTINATION");
|
||||
error_names_.emplace(move_result::E_NO_ROUTE, "move_result::E_NO_ROUTE");
|
||||
|
||||
error_names_.emplace(recall_result::E_NOT_AVAILABLE_FOR_RECALLING, "recall_result::E_NOT_AVAILABLE_FOR_RECALLING");
|
||||
|
|
|
@ -174,7 +174,6 @@ public:
|
|||
E_INCAPACITATED_UNIT = 2004,
|
||||
E_AMBUSHED = 2005,
|
||||
E_FAILED_TELEPORT = 2006,
|
||||
E_NOT_REACHED_DESTINATION = 2007,
|
||||
E_NO_ROUTE = 2008
|
||||
};
|
||||
|
||||
|
|
|
@ -112,7 +112,48 @@ public:
|
|||
value_to_cfg(value,cfg);
|
||||
return cfg;
|
||||
}
|
||||
};
|
||||
|
||||
class leader_aspects_visitor : public boost::static_visitor<std::string> {
|
||||
public:
|
||||
std::string operator()(const bool b) const {
|
||||
if (b) {
|
||||
return "yes";
|
||||
} else {
|
||||
return "no";
|
||||
}
|
||||
}
|
||||
std::string operator()(const std::vector<std::string> s) const { return utils::join(s); }
|
||||
};
|
||||
|
||||
template<>
|
||||
class config_value_translator< boost::variant<bool, std::vector<std::string>> > {
|
||||
public:
|
||||
|
||||
static boost::variant<bool, std::vector<std::string>> cfg_to_value(const config &cfg)
|
||||
{
|
||||
if (cfg["value"].to_bool(true) == cfg["value"].to_bool(false)) {
|
||||
return cfg["value"].to_bool();
|
||||
}
|
||||
return utils::split(cfg["value"]);
|
||||
}
|
||||
|
||||
static void cfg_to_value(const config &cfg, boost::variant<bool, std::vector<std::string>> &value)
|
||||
{
|
||||
value = cfg_to_value(cfg);
|
||||
}
|
||||
|
||||
static void value_to_cfg(const boost::variant<bool, std::vector<std::string>> &value, config &cfg)
|
||||
{
|
||||
cfg["value"] = boost::apply_visitor(leader_aspects_visitor(), value);
|
||||
}
|
||||
|
||||
static config value_to_cfg(const boost::variant<bool, std::vector<std::string>> &value)
|
||||
{
|
||||
config cfg;
|
||||
value_to_cfg(value,cfg);
|
||||
return cfg;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
|
|
@ -712,12 +712,12 @@ config readonly_context_impl::get_leader_goal() const
|
|||
}
|
||||
|
||||
|
||||
bool readonly_context_impl::get_leader_ignores_keep() const
|
||||
boost::variant<bool, std::vector<std::string>> readonly_context_impl::get_leader_ignores_keep() const
|
||||
{
|
||||
if (leader_ignores_keep_) {
|
||||
return leader_ignores_keep_->get();
|
||||
}
|
||||
return false;
|
||||
return boost::variant<bool, std::vector<std::string>>();
|
||||
}
|
||||
|
||||
|
||||
|
@ -730,21 +730,21 @@ double readonly_context_impl::get_leader_value() const
|
|||
}
|
||||
|
||||
|
||||
bool readonly_context_impl::get_passive_leader() const
|
||||
boost::variant<bool, std::vector<std::string>> readonly_context_impl::get_passive_leader() const
|
||||
{
|
||||
if (passive_leader_) {
|
||||
return passive_leader_->get();
|
||||
}
|
||||
return false;
|
||||
return boost::variant<bool, std::vector<std::string>>();
|
||||
}
|
||||
|
||||
|
||||
bool readonly_context_impl::get_passive_leader_shares_keep() const
|
||||
boost::variant<bool, std::vector<std::string>> readonly_context_impl::get_passive_leader_shares_keep() const
|
||||
{
|
||||
if (passive_leader_shares_keep_) {
|
||||
return passive_leader_shares_keep_->get();
|
||||
}
|
||||
return false;
|
||||
return boost::variant<bool, std::vector<std::string>>();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1149,7 +1149,7 @@ void readonly_context_impl::recalculate_move_maps() const
|
|||
possible_moves_ = moves_map();
|
||||
srcdst_ = move_map();
|
||||
calculate_possible_moves(possible_moves_,srcdst_,dstsrc_,false,false,&get_avoid());
|
||||
if (get_passive_leader()||get_passive_leader_shares_keep()) {
|
||||
if (is_passive_leader("") && !is_passive_keep_sharing_leader("")) {
|
||||
unit_map::iterator i = resources::gameboard->units().find_leader(get_side());
|
||||
if (i.valid()) {
|
||||
map_location loc = i->get_location();
|
||||
|
@ -1277,4 +1277,34 @@ bool readonly_context_impl::is_active(const std::string &time_of_day, const std:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool readonly_context_impl::applies_to_leader(const boost::variant<bool, std::vector<std::string>> &aspect_value, const std::string &id) const
|
||||
{
|
||||
if (aspect_value.which() == 0) {
|
||||
return boost::get<bool>(aspect_value);
|
||||
} else {
|
||||
std::vector<std::string> aspect_ids = boost::get<std::vector<std::string>>(aspect_value);
|
||||
for(std::vector<std::string>::const_iterator aspect_id = aspect_ids.begin(); aspect_id != aspect_ids.end() ; ++aspect_id ) {
|
||||
if(*aspect_id == id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool readonly_context_impl::is_keep_ignoring_leader(const std::string &id) const
|
||||
{
|
||||
return applies_to_leader(leader_ignores_keep_->get(), id);
|
||||
}
|
||||
|
||||
bool readonly_context_impl::is_passive_leader(const std::string &id) const
|
||||
{
|
||||
return applies_to_leader(passive_leader_->get(), id);
|
||||
}
|
||||
|
||||
bool readonly_context_impl::is_passive_keep_sharing_leader(const std::string &id) const
|
||||
{
|
||||
return applies_to_leader(passive_leader_shares_keep_->get(), id);
|
||||
}
|
||||
|
||||
} //of namespace ai
|
||||
|
|
|
@ -276,16 +276,16 @@ public:
|
|||
virtual config get_leader_goal() const = 0;
|
||||
|
||||
|
||||
virtual bool get_leader_ignores_keep() const = 0;
|
||||
virtual boost::variant<bool, std::vector<std::string>> get_leader_ignores_keep() const = 0;
|
||||
|
||||
|
||||
virtual double get_leader_value() const = 0;
|
||||
|
||||
|
||||
virtual bool get_passive_leader() const = 0;
|
||||
virtual boost::variant<bool, std::vector<std::string>> get_passive_leader() const = 0;
|
||||
|
||||
|
||||
virtual bool get_passive_leader_shares_keep() const = 0;
|
||||
virtual boost::variant<bool, std::vector<std::string>> get_passive_leader_shares_keep() const = 0;
|
||||
|
||||
|
||||
virtual const moves_map& get_possible_moves() const = 0;
|
||||
|
@ -330,6 +330,12 @@ public:
|
|||
|
||||
virtual bool is_active(const std::string &time_of_day, const std::string &turns) const = 0;
|
||||
|
||||
virtual bool is_keep_ignoring_leader(const std::string &id) const = 0;
|
||||
|
||||
virtual bool is_passive_leader(const std::string &id) const = 0;
|
||||
|
||||
virtual bool is_passive_keep_sharing_leader(const std::string &id) const = 0;
|
||||
|
||||
virtual bool is_dst_src_valid_lua() const = 0;
|
||||
|
||||
virtual bool is_dst_src_enemy_valid_lua() const = 0;
|
||||
|
@ -752,7 +758,7 @@ public:
|
|||
}
|
||||
|
||||
|
||||
virtual bool get_leader_ignores_keep() const override
|
||||
virtual boost::variant<bool, std::vector<std::string>> get_leader_ignores_keep() const override
|
||||
{
|
||||
return target_->get_leader_ignores_keep();
|
||||
}
|
||||
|
@ -764,13 +770,13 @@ public:
|
|||
}
|
||||
|
||||
|
||||
virtual bool get_passive_leader() const override
|
||||
virtual boost::variant<bool, std::vector<std::string>> get_passive_leader() const override
|
||||
{
|
||||
return target_->get_passive_leader();
|
||||
}
|
||||
|
||||
|
||||
virtual bool get_passive_leader_shares_keep() const override
|
||||
virtual boost::variant<bool, std::vector<std::string>> get_passive_leader_shares_keep() const override
|
||||
{
|
||||
return target_->get_passive_leader_shares_keep();
|
||||
}
|
||||
|
@ -866,6 +872,21 @@ public:
|
|||
return target_->is_active(time_of_day, turns);
|
||||
}
|
||||
|
||||
virtual bool is_keep_ignoring_leader(const std::string &id) const override
|
||||
{
|
||||
return target_->is_keep_ignoring_leader(id);
|
||||
}
|
||||
|
||||
virtual bool is_passive_leader(const std::string &id) const override
|
||||
{
|
||||
return target_->is_passive_leader(id);
|
||||
}
|
||||
|
||||
virtual bool is_passive_keep_sharing_leader(const std::string &id) const override
|
||||
{
|
||||
return target_->is_passive_keep_sharing_leader(id);
|
||||
}
|
||||
|
||||
virtual bool is_dst_src_valid_lua() const override
|
||||
{
|
||||
return target_->is_dst_src_valid_lua();
|
||||
|
@ -1351,16 +1372,16 @@ public:
|
|||
virtual config get_leader_goal() const override;
|
||||
|
||||
|
||||
virtual bool get_leader_ignores_keep() const override;
|
||||
virtual boost::variant<bool, std::vector<std::string>> get_leader_ignores_keep() const override;
|
||||
|
||||
|
||||
virtual double get_leader_value() const override;
|
||||
|
||||
|
||||
virtual bool get_passive_leader() const override;
|
||||
virtual boost::variant<bool, std::vector<std::string>> get_passive_leader() const override;
|
||||
|
||||
|
||||
virtual bool get_passive_leader_shares_keep() const override;
|
||||
virtual boost::variant<bool, std::vector<std::string>> get_passive_leader_shares_keep() const override;
|
||||
|
||||
|
||||
virtual const moves_map& get_possible_moves() const override;
|
||||
|
@ -1404,6 +1425,12 @@ public:
|
|||
|
||||
virtual bool is_active(const std::string &time_of_day, const std::string &turns) const override;
|
||||
|
||||
virtual bool is_keep_ignoring_leader(const std::string &id) const override;
|
||||
|
||||
virtual bool is_passive_leader(const std::string &id) const override;
|
||||
|
||||
virtual bool is_passive_keep_sharing_leader(const std::string &id) const override;
|
||||
|
||||
virtual bool is_dst_src_valid_lua() const override;
|
||||
|
||||
virtual bool is_dst_src_enemy_valid_lua() const override;
|
||||
|
@ -1467,6 +1494,8 @@ private:
|
|||
template<typename T>
|
||||
void add_known_aspect(const std::string &name, typesafe_aspect_ptr<T>& where);
|
||||
|
||||
bool applies_to_leader(const boost::variant<bool, std::vector<std::string>> &aspect_value, const std::string &id) const;
|
||||
|
||||
const config cfg_;
|
||||
|
||||
/**
|
||||
|
@ -1492,7 +1521,7 @@ private:
|
|||
mutable keeps_cache keeps_;
|
||||
typesafe_aspect_ptr<double> leader_aggression_;
|
||||
typesafe_aspect_ptr<config> leader_goal_;
|
||||
typesafe_aspect_ptr<bool> leader_ignores_keep_;
|
||||
typesafe_aspect_ptr<boost::variant<bool, std::vector<std::string>>> leader_ignores_keep_;
|
||||
typesafe_aspect_ptr<double> leader_value_;
|
||||
mutable bool move_maps_enemy_valid_;
|
||||
mutable bool move_maps_valid_;
|
||||
|
@ -1500,8 +1529,8 @@ private:
|
|||
mutable bool dst_src_enemy_valid_lua_;
|
||||
mutable bool src_dst_valid_lua_;
|
||||
mutable bool src_dst_enemy_valid_lua_;
|
||||
typesafe_aspect_ptr<bool> passive_leader_;
|
||||
typesafe_aspect_ptr<bool> passive_leader_shares_keep_;
|
||||
typesafe_aspect_ptr<boost::variant<bool, std::vector<std::string>>> passive_leader_;
|
||||
typesafe_aspect_ptr<boost::variant<bool, std::vector<std::string>>> passive_leader_shares_keep_;
|
||||
mutable moves_map possible_moves_;
|
||||
typesafe_aspect_ptr<double> recruitment_diversity_;
|
||||
typesafe_aspect_ptr<config> recruitment_instructions_;
|
||||
|
|
|
@ -82,7 +82,7 @@ std::shared_ptr<attacks_vector> aspect_attacks_base::analyze_targets() const
|
|||
|
||||
std::vector<map_location> unit_locs;
|
||||
for(unit_map::const_iterator i = units_.begin(); i != units_.end(); ++i) {
|
||||
if (i->side() == get_side() && i->attacks_left() && !(i->can_recruit() && get_passive_leader())) {
|
||||
if (i->side() == get_side() && i->attacks_left() && !(i->can_recruit() && is_passive_leader(i->id()))) {
|
||||
if (!is_allowed_attacker(*i)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ double goto_phase::evaluate()
|
|||
for(std::vector<map_location>::const_iterator g = gotos.begin(); g != gotos.end(); ++g) {
|
||||
unit_map::const_iterator ui = units_.find(*g);
|
||||
// passive_leader: never moves or attacks
|
||||
if(ui->can_recruit() && get_passive_leader() && !get_passive_leader_shares_keep()){
|
||||
if(ui->can_recruit() && is_passive_leader(ui->id())){
|
||||
continue;
|
||||
}
|
||||
// end of passive_leader
|
||||
|
@ -407,10 +407,7 @@ move_leader_to_keep_phase::~move_leader_to_keep_phase()
|
|||
|
||||
double move_leader_to_keep_phase::evaluate()
|
||||
{
|
||||
if (get_leader_ignores_keep()) {
|
||||
return BAD_SCORE;
|
||||
}
|
||||
if (get_passive_leader() && !get_passive_leader_shares_keep()) {
|
||||
if (is_keep_ignoring_leader("")) {
|
||||
return BAD_SCORE;
|
||||
}
|
||||
|
||||
|
@ -434,7 +431,7 @@ double move_leader_to_keep_phase::evaluate()
|
|||
int shortest_distance = 99999;
|
||||
|
||||
for (const unit_map::const_iterator& leader : leaders) {
|
||||
if (leader->incapacitated() || leader->movement_left() == 0 || !is_allowed_unit(*leader)) {
|
||||
if (leader->incapacitated() || leader->movement_left() == 0 || !is_allowed_unit(*leader) || is_keep_ignoring_leader(leader->id()) || (is_passive_leader(leader->id()) && !is_passive_keep_sharing_leader(leader->id()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -638,7 +635,7 @@ void get_villages_phase::get_villages(
|
|||
treachmap reachmap;
|
||||
for(unit_map::const_iterator u_itor = units_.begin();
|
||||
u_itor != units_.end(); ++u_itor) {
|
||||
if(u_itor->can_recruit() && get_passive_leader()){
|
||||
if(u_itor->can_recruit() && is_passive_leader(u_itor->id())){
|
||||
continue;
|
||||
}
|
||||
if(u_itor->side() == get_side() && u_itor->movement_left() && is_allowed_unit(*u_itor)) {
|
||||
|
@ -685,8 +682,6 @@ void get_villages_phase::find_villages(
|
|||
{
|
||||
std::map<map_location, double> vulnerability;
|
||||
|
||||
const bool passive_leader = get_passive_leader();
|
||||
|
||||
std::size_t min_distance = 100000;
|
||||
const gamemap &map_ = resources::gameboard->map();
|
||||
std::vector<team> &teams_ = resources::gameboard->teams();
|
||||
|
@ -701,10 +696,6 @@ void get_villages_phase::find_villages(
|
|||
const map_location ¤t_loc = j->first;
|
||||
|
||||
if(j->second == leader_loc_) {
|
||||
if(passive_leader) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::size_t distance = distance_between(keep_loc_, current_loc);
|
||||
if(distance < min_distance) {
|
||||
min_distance = distance;
|
||||
|
@ -753,7 +744,7 @@ void get_villages_phase::find_villages(
|
|||
}
|
||||
|
||||
const unit_map::const_iterator u = resources::gameboard->units().find(j->second);
|
||||
if (u == resources::gameboard->units().end() || u->get_state("guardian") || !is_allowed_unit(*u)) {
|
||||
if (u == resources::gameboard->units().end() || u->get_state("guardian") || !is_allowed_unit(*u) || (u->can_recruit() && is_passive_leader(u->id()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1351,7 +1342,7 @@ double get_healing_phase::evaluate()
|
|||
for(; u_it != units_.end(); ++u_it) {
|
||||
unit &u = *u_it;
|
||||
|
||||
if(u.can_recruit() && get_passive_leader()){
|
||||
if(u.can_recruit() && is_passive_leader(u.id())){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1613,9 +1604,18 @@ leader_shares_keep_phase::~leader_shares_keep_phase()
|
|||
|
||||
double leader_shares_keep_phase::evaluate()
|
||||
{
|
||||
if(get_passive_leader() && !get_passive_leader_shares_keep()){
|
||||
bool have_active_leader = false;
|
||||
std::vector<unit_map::unit_iterator> ai_leaders = resources::gameboard->units().find_leaders(get_side());
|
||||
for (unit_map::unit_iterator &ai_leader : ai_leaders) {
|
||||
if (!is_passive_leader(ai_leader->id()) || is_passive_keep_sharing_leader(ai_leader->id())) {
|
||||
have_active_leader = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!have_active_leader) {
|
||||
return BAD_SCORE;
|
||||
}
|
||||
|
||||
bool allied_leaders_available = false;
|
||||
for(team &tmp_team : resources::gameboard->teams()) {
|
||||
if(!current_team().is_enemy(tmp_team.side())){
|
||||
|
@ -1645,7 +1645,7 @@ void leader_shares_keep_phase::execute()
|
|||
|
||||
//check for each ai leader if he should move away from his keep
|
||||
for (unit_map::unit_iterator &ai_leader : ai_leaders) {
|
||||
if(!ai_leader.valid() || !is_allowed_unit(*ai_leader)) {
|
||||
if(!ai_leader.valid() || !is_allowed_unit(*ai_leader) || (is_passive_leader(ai_leader->id()) && !is_passive_keep_sharing_leader(ai_leader->id()))) {
|
||||
//This can happen if wml killed or moved a leader during a movement events of another leader
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -280,7 +280,7 @@ std::pair<map_location,map_location> move_to_targets_phase::choose_move(std::vec
|
|||
|
||||
//take care of all the guardians first
|
||||
for(u = units_.begin(); u != units_.end(); ++u) {
|
||||
if (!(u->side() != get_side() || (u->can_recruit() && !get_leader_ignores_keep()) || u->movement_left() <= 0 || u->incapacitated())) {
|
||||
if (!(u->side() != get_side() || (u->can_recruit() && !is_keep_ignoring_leader(u->id())) || u->movement_left() <= 0 || u->incapacitated())) {
|
||||
if (u->get_state("guardian")) {
|
||||
LOG_AI << u->type_id() << " is guardian, staying still\n";
|
||||
return std::make_pair(u->get_location(), u->get_location());
|
||||
|
@ -290,7 +290,7 @@ std::pair<map_location,map_location> move_to_targets_phase::choose_move(std::vec
|
|||
|
||||
//now find the first eligible remaining unit
|
||||
for(u = units_.begin(); u != units_.end(); ++u) {
|
||||
if (!(u->side() != get_side() || (u->can_recruit() && !get_leader_ignores_keep()) || u->movement_left() <= 0 || u->incapacitated() || !is_allowed_unit(*u))) {
|
||||
if (!(u->side() != get_side() || (u->can_recruit() && !is_keep_ignoring_leader(u->id())) || u->movement_left() <= 0 || u->incapacitated() || !is_allowed_unit(*u))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -391,7 +391,7 @@ std::pair<map_location,map_location> move_to_targets_phase::choose_move(std::vec
|
|||
LOG_AI << "complex targeting...\n";
|
||||
//now see if any other unit can put a better bid forward
|
||||
for(++u; u != units_.end(); ++u) {
|
||||
if (u->side() != get_side() || (u->can_recruit() && !get_leader_ignores_keep()) ||
|
||||
if (u->side() != get_side() || (u->can_recruit() && !is_keep_ignoring_leader(u->id())) ||
|
||||
u->movement_left() <= 0 || u->get_state("guardian") ||
|
||||
u->incapacitated() || !is_allowed_unit(*u))
|
||||
{
|
||||
|
@ -694,7 +694,7 @@ map_location move_to_targets_phase::form_group(const std::vector<map_location>&
|
|||
++n;
|
||||
} else {
|
||||
const unit_map::const_iterator un = units_.find(j->second);
|
||||
if(un == units_.end() || (un->can_recruit() && !get_leader_ignores_keep()) || un->movement_left() < un->total_movement()) {
|
||||
if(un == units_.end() || (un->can_recruit() && !is_keep_ignoring_leader(un->id())) || un->movement_left() < un->total_movement()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -312,7 +312,17 @@ variant formula_ai::get_value(const std::string& key) const
|
|||
|
||||
} else if(key == "leader_ignores_keep")
|
||||
{
|
||||
return variant(get_leader_ignores_keep());
|
||||
boost::variant<bool, std::vector<std::string>> leader_ignores_keep = get_leader_ignores_keep();
|
||||
if (leader_ignores_keep.which() == 0) {
|
||||
return variant(boost::get<bool>(leader_ignores_keep));
|
||||
} else {
|
||||
std::vector<std::string> &strlist = boost::get<std::vector<std::string>>(leader_ignores_keep);
|
||||
std::vector<variant> vars;
|
||||
for(const std::string &i : strlist) {
|
||||
vars.emplace_back(i);
|
||||
}
|
||||
return variant(vars);
|
||||
}
|
||||
|
||||
} else if(key == "leader_value")
|
||||
{
|
||||
|
@ -320,11 +330,31 @@ variant formula_ai::get_value(const std::string& key) const
|
|||
|
||||
} else if(key == "passive_leader")
|
||||
{
|
||||
return variant(get_passive_leader());
|
||||
boost::variant<bool, std::vector<std::string>> passive_leader = get_passive_leader();
|
||||
if (passive_leader.which() == 0) {
|
||||
return variant(boost::get<bool>(passive_leader));
|
||||
} else {
|
||||
std::vector<std::string> &strlist = boost::get<std::vector<std::string>>(passive_leader);
|
||||
std::vector<variant> vars;
|
||||
for(const std::string &i : strlist) {
|
||||
vars.emplace_back(i);
|
||||
}
|
||||
return variant(vars);
|
||||
}
|
||||
|
||||
} else if(key == "passive_leader_shares_keep")
|
||||
{
|
||||
return variant(get_passive_leader_shares_keep());
|
||||
boost::variant<bool, std::vector<std::string>> passive_leader_shares_keep = get_passive_leader_shares_keep();
|
||||
if (passive_leader_shares_keep.which() == 0) {
|
||||
return variant(boost::get<bool>(passive_leader_shares_keep));
|
||||
} else {
|
||||
std::vector<std::string> &strlist = boost::get<std::vector<std::string>>(passive_leader_shares_keep);
|
||||
std::vector<variant> vars;
|
||||
for(const std::string &i : strlist) {
|
||||
vars.emplace_back(i);
|
||||
}
|
||||
return variant(vars);
|
||||
}
|
||||
|
||||
} else if(key == "recruitment_pattern")
|
||||
{
|
||||
|
|
|
@ -438,8 +438,17 @@ static int cfun_ai_get_leader_goal(lua_State *L)
|
|||
static int cfun_ai_get_leader_ignores_keep(lua_State *L)
|
||||
{
|
||||
DEPRECATED_ASPECT_MESSAGE("leader_ignores_keep");
|
||||
bool leader_ignores_keep = get_readonly_context(L).get_leader_ignores_keep();
|
||||
lua_pushboolean(L, leader_ignores_keep);
|
||||
boost::variant<bool, std::vector<std::string>> leader_ignores_keep = get_readonly_context(L).get_leader_ignores_keep();
|
||||
if (leader_ignores_keep.which() == 0) {
|
||||
lua_pushboolean(L, boost::get<bool>(leader_ignores_keep));
|
||||
} else {
|
||||
std::vector<std::string> strlist = boost::get<std::vector<std::string>>(leader_ignores_keep);
|
||||
lua_createtable(L, strlist.size(), 0);
|
||||
for(const std::string& str : strlist) {
|
||||
lua_pushlstring(L, str.c_str(), str.size());
|
||||
lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -454,16 +463,34 @@ static int cfun_ai_get_leader_value(lua_State *L)
|
|||
static int cfun_ai_get_passive_leader(lua_State *L)
|
||||
{
|
||||
DEPRECATED_ASPECT_MESSAGE("passive_leader");
|
||||
bool passive_leader = get_readonly_context(L).get_passive_leader();
|
||||
lua_pushboolean(L, passive_leader);
|
||||
boost::variant<bool, std::vector<std::string>> passive_leader = get_readonly_context(L).get_passive_leader();
|
||||
if (passive_leader.which() == 0) {
|
||||
lua_pushboolean(L, boost::get<bool>(passive_leader));
|
||||
} else {
|
||||
std::vector<std::string> strlist = boost::get<std::vector<std::string>>(passive_leader);
|
||||
lua_createtable(L, strlist.size(), 0);
|
||||
for(const std::string& str : strlist) {
|
||||
lua_pushlstring(L, str.c_str(), str.size());
|
||||
lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int cfun_ai_get_passive_leader_shares_keep(lua_State *L)
|
||||
{
|
||||
DEPRECATED_ASPECT_MESSAGE("passive_leader_shares_keep");
|
||||
bool passive_leader_shares_keep = get_readonly_context(L).get_passive_leader_shares_keep();
|
||||
lua_pushboolean(L, passive_leader_shares_keep);
|
||||
boost::variant<bool, std::vector<std::string>> passive_leader_shares_keep = get_readonly_context(L).get_passive_leader_shares_keep();
|
||||
if (passive_leader_shares_keep.which() == 0) {
|
||||
lua_pushboolean(L, boost::get<bool>(passive_leader_shares_keep));
|
||||
} else {
|
||||
std::vector<std::string> strlist = boost::get<std::vector<std::string>>(passive_leader_shares_keep);
|
||||
lua_createtable(L, strlist.size(), 0);
|
||||
for(const std::string& str : strlist) {
|
||||
lua_pushlstring(L, str.c_str(), str.size());
|
||||
lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "ai/default/contexts.hpp"
|
||||
#include "ai/lua/aspect_advancements.hpp"
|
||||
|
||||
#include <boost/variant/get.hpp>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -118,6 +119,44 @@ inline std::shared_ptr<std::string> lua_object<std::string>::to_type(lua_State *
|
|||
return std::make_shared<std::string>(lua_tostring(L, n));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void lua_object<boost::variant<bool, std::vector<std::string>>>::from_type(lua_State *L, std::shared_ptr<boost::variant<bool, std::vector<std::string>>> value)
|
||||
{
|
||||
if(value) {
|
||||
if (value->which() == 0) {
|
||||
lua_pushboolean(L, boost::get<bool>(*value));
|
||||
} else {
|
||||
std::vector<std::string> strlist = boost::get<std::vector<std::string>>(*value);
|
||||
lua_createtable(L, strlist.size(), 0);
|
||||
for(const std::string& str : strlist) {
|
||||
lua_pushlstring(L, str.c_str(), str.size());
|
||||
lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
|
||||
}
|
||||
}
|
||||
} else lua_pushnil(L);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::shared_ptr< boost::variant<bool, std::vector<std::string>> > lua_object< boost::variant<bool, std::vector<std::string>> >::to_type(lua_State *L, int n)
|
||||
{
|
||||
if (lua_isboolean(L, n)) {
|
||||
return std::make_shared<boost::variant<bool, std::vector<std::string>>>(luaW_toboolean(L, n));
|
||||
} else {
|
||||
std::shared_ptr<std::vector<std::string>> v(new std::vector<std::string>());
|
||||
int l = lua_rawlen(L, n);
|
||||
for (int i = 1; i < l + 1; ++i)
|
||||
{
|
||||
lua_pushinteger(L, i);
|
||||
lua_gettable(L, n);
|
||||
std::string s = lua_tostring(L, -1);
|
||||
lua_settop(L, n);
|
||||
v->push_back(s);
|
||||
}
|
||||
|
||||
return std::make_shared<boost::variant<bool, std::vector<std::string>>>(*v);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void lua_object<std::string>::from_type(lua_State *L, std::shared_ptr<std::string> value)
|
||||
{
|
||||
|
@ -175,7 +214,7 @@ inline void lua_object< std::vector<std::string> >::from_type(lua_State *L, std:
|
|||
lua_createtable(L, value->size(), 0);
|
||||
for(const std::string& str : *value) {
|
||||
lua_pushlstring(L, str.c_str(), str.size());
|
||||
lua_rawseti(L, -1, lua_rawlen(L, -2) + 1);
|
||||
lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
|
||||
}
|
||||
} else lua_pushnil(L);
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "ai/composite/ai.hpp" // for ai_composite
|
||||
#include "ai/composite/component.hpp" // for component_manager
|
||||
#include "ai/composite/engine.hpp" // for engine
|
||||
#include "ai/composite/value_translator.hpp"
|
||||
#include "ai/configuration.hpp" // for configuration
|
||||
#include "ai/contexts.hpp" // for readonly_context, etc
|
||||
#include "ai/default/contexts.hpp" // for default_ai_context, etc
|
||||
|
@ -234,16 +235,24 @@ const std::string holder::get_ai_overview()
|
|||
if (!this->ai_) {
|
||||
get_ai_ref();
|
||||
}
|
||||
// These assignments are necessary because the code will otherwise not compile on some platforms with an lvalue/rvalue mismatch error
|
||||
boost::variant<bool, std::vector<std::string>> lik = this->ai_->get_leader_ignores_keep();
|
||||
boost::variant<bool, std::vector<std::string>> pl = this->ai_->get_passive_leader();
|
||||
boost::variant<bool, std::vector<std::string>> plsk = this->ai_->get_passive_leader_shares_keep();
|
||||
// In order to display booleans as yes/no rather than 1/0 or true/false
|
||||
config cfg;
|
||||
cfg["simple_targeting"] = this->ai_->get_simple_targeting();
|
||||
cfg["support_villages"] = this->ai_->get_support_villages();
|
||||
std::stringstream s;
|
||||
s << "advancements: " << this->ai_->get_advancements().get_value() << std::endl;
|
||||
s << "aggression: " << this->ai_->get_aggression() << std::endl;
|
||||
s << "caution: " << this->ai_->get_caution() << std::endl;
|
||||
s << "grouping: " << this->ai_->get_grouping() << std::endl;
|
||||
s << "leader_aggression: " << this->ai_->get_leader_aggression() << std::endl;
|
||||
s << "leader_ignores_keep: " << this->ai_->get_leader_ignores_keep() << std::endl;
|
||||
s << "leader_ignores_keep: " << boost::apply_visitor(leader_aspects_visitor(), lik) << std::endl;
|
||||
s << "leader_value: " << this->ai_->get_leader_value() << std::endl;
|
||||
s << "passive_leader: " << this->ai_->get_passive_leader() << std::endl;
|
||||
s << "passive_leader_shares_keep: " << this->ai_->get_passive_leader_shares_keep() << std::endl;
|
||||
s << "passive_leader: " << boost::apply_visitor(leader_aspects_visitor(), pl) << std::endl;
|
||||
s << "passive_leader_shares_keep: " << boost::apply_visitor(leader_aspects_visitor(), plsk) << std::endl;
|
||||
s << "recruitment_diversity: " << this->ai_->get_recruitment_diversity() << std::endl;
|
||||
s << "recruitment_instructions: " << std::endl << "----config begin----" << std::endl;
|
||||
s << this->ai_->get_recruitment_instructions() << "-----config end-----" << std::endl;
|
||||
|
@ -253,8 +262,8 @@ const std::string holder::get_ai_overview()
|
|||
s << "recruitment_save_gold: " << std::endl << "----config begin----" << std::endl;
|
||||
s << this->ai_->get_recruitment_save_gold() << "-----config end-----" << std::endl;
|
||||
s << "scout_village_targeting: " << this->ai_->get_scout_village_targeting() << std::endl;
|
||||
s << "simple_targeting: " << this->ai_->get_simple_targeting() << std::endl;
|
||||
s << "support_villages: " << this->ai_->get_support_villages() << std::endl;
|
||||
s << "simple_targeting: " << cfg["simple_targeting"] << std::endl;
|
||||
s << "support_villages: " << cfg["support_villages"] << std::endl;
|
||||
s << "village_value: " << this->ai_->get_village_value() << std::endl;
|
||||
s << "villages_per_scout: " << this->ai_->get_villages_per_scout() << std::endl;
|
||||
|
||||
|
|
|
@ -206,16 +206,16 @@ static register_aspect_factory< composite_aspect<double>>
|
|||
static register_aspect_factory< composite_aspect<config>>
|
||||
leader_goal__composite_aspect_factory("leader_goal*composite_aspect");
|
||||
|
||||
static register_aspect_factory< composite_aspect<bool>>
|
||||
static register_aspect_factory< composite_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
leader_igores_keep__composite_aspect_factory("leader_ignores_keep*composite_aspect");
|
||||
|
||||
static register_aspect_factory< composite_aspect<double>>
|
||||
leader_value__composite_aspect_factory("leader_value*composite_aspect");
|
||||
|
||||
static register_aspect_factory< composite_aspect<bool>>
|
||||
static register_aspect_factory< composite_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
passive_leader__composite_aspect_factory("passive_leader*composite_aspect");
|
||||
|
||||
static register_aspect_factory< composite_aspect<bool>>
|
||||
static register_aspect_factory< composite_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
passive_leader_shares_keep__composite_aspect_factory("passive_leader_shares_keep*composite_aspect");
|
||||
|
||||
static register_aspect_factory< composite_aspect<double>>
|
||||
|
@ -277,16 +277,16 @@ static register_aspect_factory< standard_aspect<double>>
|
|||
static register_aspect_factory< standard_aspect<config>>
|
||||
leader_goal__standard_aspect_factory("leader_goal*standard_aspect");
|
||||
|
||||
static register_aspect_factory< standard_aspect<bool>>
|
||||
static register_aspect_factory< standard_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
leader_ignores_keep__standard_aspect_factory("leader_ignores_keep*standard_aspect");
|
||||
|
||||
static register_aspect_factory< standard_aspect<double>>
|
||||
leader_value__standard_aspect_factory("leader_value*standard_aspect");
|
||||
|
||||
static register_aspect_factory< standard_aspect<bool>>
|
||||
static register_aspect_factory< standard_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
passive_leader__standard_aspect_factory("passive_leader*standard_aspect");
|
||||
|
||||
static register_aspect_factory< standard_aspect<bool>>
|
||||
static register_aspect_factory< standard_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
passive_leader_shares_keep__standard_aspect_factory("passive_leader_shares_keep*standard_aspect");
|
||||
|
||||
static register_aspect_factory< standard_aspect<double>>
|
||||
|
@ -352,16 +352,16 @@ static register_aspect_factory< standard_aspect<double>>
|
|||
static register_aspect_factory< standard_aspect<config>>
|
||||
leader_goal__standard_aspect_factory2("leader_goal*");
|
||||
|
||||
static register_aspect_factory< standard_aspect<bool>>
|
||||
static register_aspect_factory< standard_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
leader_ignores_keep__standard_aspect_factory2("leader_ignores_keep*");
|
||||
|
||||
static register_aspect_factory< standard_aspect<double>>
|
||||
leader_value__standard_aspect_factory2("leader_value*");
|
||||
|
||||
static register_aspect_factory< standard_aspect<bool>>
|
||||
static register_aspect_factory< standard_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
passive_leader__standard_aspect_factory2("passive_leader*");
|
||||
|
||||
static register_aspect_factory< standard_aspect<bool>>
|
||||
static register_aspect_factory< standard_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
passive_leader_shares_keep__standard_aspect_factory2("passive_leader_shares_keep*");
|
||||
|
||||
static register_aspect_factory< standard_aspect<double>>
|
||||
|
@ -423,16 +423,16 @@ static register_lua_aspect_factory< lua_aspect<double>>
|
|||
static register_lua_aspect_factory< lua_aspect<config>>
|
||||
leader_goal__lua_aspect_factory("leader_goal*lua_aspect");
|
||||
|
||||
static register_lua_aspect_factory< lua_aspect<bool>>
|
||||
static register_lua_aspect_factory< lua_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
leader_ignores_keep__lua_aspect_factory("leader_ignores_keep*lua_aspect");
|
||||
|
||||
static register_lua_aspect_factory< lua_aspect<double>>
|
||||
leader_value__lua_aspect_factory("leader_value*lua_aspect");
|
||||
|
||||
static register_lua_aspect_factory< lua_aspect<bool>>
|
||||
static register_lua_aspect_factory< lua_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
passive_leader__lua_aspect_factory("passive_leader*lua_aspect");
|
||||
|
||||
static register_lua_aspect_factory< lua_aspect<bool>>
|
||||
static register_lua_aspect_factory< lua_aspect<boost::variant<bool, std::vector<std::string>>>>
|
||||
passive_leader_shares_keep__lua_aspect_factory("passive_leader_shares_keep*lua_aspect");
|
||||
|
||||
static register_lua_aspect_factory< lua_aspect<double>>
|
||||
|
|
Loading…
Add table
Reference in a new issue