Merge pull request #4588 from mattsc/various_ai_features

Implement various AI feature requests and fixes
This commit is contained in:
mattsc 2020-01-01 16:47:57 -08:00 committed by GitHub
commit a7aa08c90a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 322 additions and 81 deletions

View file

@ -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 } }

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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})

View file

@ -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");

View file

@ -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
};

View file

@ -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<>

View file

@ -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

View file

@ -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_;

View file

@ -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;
}

View file

@ -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 &current_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;
}

View file

@ -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;
}

View file

@ -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")
{

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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>>