AI: allow list of ids for two passive leader aspects
In addition to 'yes' and 'no', comma separated lists of leader ids are now also accepted as values for these aspects. This allows setting the behavior only for specific leaders.
This commit is contained in:
parent
96faf5b54d
commit
926662216a
10 changed files with 114 additions and 51 deletions
|
@ -1062,6 +1062,20 @@ end
|
|||
|
||||
--------- Unit related helper functions ----------
|
||||
|
||||
function ai_helper.is_passive_leader(aspect_value, id)
|
||||
if (aspect_value == 'yes') then return true end
|
||||
if (aspect_value == 'no') then return false end
|
||||
|
||||
local aspect_ids = ai_helper.split(aspect_value)
|
||||
for _,aspect_id in ipairs(aspect_ids) 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
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -730,21 +730,21 @@ double readonly_context_impl::get_leader_value() const
|
|||
}
|
||||
|
||||
|
||||
bool readonly_context_impl::get_passive_leader() const
|
||||
std::string readonly_context_impl::get_passive_leader() const
|
||||
{
|
||||
if (passive_leader_) {
|
||||
return passive_leader_->get();
|
||||
}
|
||||
return false;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
bool readonly_context_impl::get_passive_leader_shares_keep() const
|
||||
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 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();
|
||||
|
@ -1299,4 +1299,14 @@ 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
|
||||
|
|
|
@ -282,10 +282,10 @@ public:
|
|||
virtual double get_leader_value() const = 0;
|
||||
|
||||
|
||||
virtual bool get_passive_leader() const = 0;
|
||||
virtual std::string get_passive_leader() const = 0;
|
||||
|
||||
|
||||
virtual bool get_passive_leader_shares_keep() const = 0;
|
||||
virtual std::string get_passive_leader_shares_keep() const = 0;
|
||||
|
||||
|
||||
virtual const moves_map& get_possible_moves() const = 0;
|
||||
|
@ -332,6 +332,10 @@ public:
|
|||
|
||||
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;
|
||||
|
@ -766,13 +770,13 @@ public:
|
|||
}
|
||||
|
||||
|
||||
virtual bool get_passive_leader() const override
|
||||
virtual std::string get_passive_leader() const override
|
||||
{
|
||||
return target_->get_passive_leader();
|
||||
}
|
||||
|
||||
|
||||
virtual bool get_passive_leader_shares_keep() const override
|
||||
virtual std::string get_passive_leader_shares_keep() const override
|
||||
{
|
||||
return target_->get_passive_leader_shares_keep();
|
||||
}
|
||||
|
@ -873,6 +877,16 @@ public:
|
|||
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();
|
||||
|
@ -1364,10 +1378,10 @@ public:
|
|||
virtual double get_leader_value() const override;
|
||||
|
||||
|
||||
virtual bool get_passive_leader() const override;
|
||||
virtual std::string get_passive_leader() const override;
|
||||
|
||||
|
||||
virtual bool get_passive_leader_shares_keep() const override;
|
||||
virtual std::string get_passive_leader_shares_keep() const override;
|
||||
|
||||
|
||||
virtual const moves_map& get_possible_moves() const override;
|
||||
|
@ -1413,6 +1427,10 @@ public:
|
|||
|
||||
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;
|
||||
|
@ -1511,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<std::string> passive_leader_;
|
||||
typesafe_aspect_ptr<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()){
|
||||
if(ui->can_recruit() && is_passive_leader(ui->id())){
|
||||
continue;
|
||||
}
|
||||
// end of passive_leader
|
||||
|
@ -410,9 +410,6 @@ double move_leader_to_keep_phase::evaluate()
|
|||
if (is_keep_ignoring_leader("")) {
|
||||
return BAD_SCORE;
|
||||
}
|
||||
if (get_passive_leader() && !get_passive_leader_shares_keep()) {
|
||||
return BAD_SCORE;
|
||||
}
|
||||
|
||||
// 1. Collect all leaders in a list
|
||||
// 2. Get the suitable_keep for each leader
|
||||
|
@ -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) || is_keep_ignoring_leader(leader->id())) {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -454,16 +454,16 @@ 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);
|
||||
std::string passive_leader = get_readonly_context(L).get_passive_leader();
|
||||
lua_pushstring(L, passive_leader.c_str());
|
||||
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);
|
||||
std::string passive_leader_shares_keep = get_readonly_context(L).get_passive_leader_shares_keep();
|
||||
lua_pushstring(L, passive_leader_shares_keep.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -212,10 +212,10 @@ static register_aspect_factory< composite_aspect<std::string>>
|
|||
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<std::string>>
|
||||
passive_leader__composite_aspect_factory("passive_leader*composite_aspect");
|
||||
|
||||
static register_aspect_factory< composite_aspect<bool>>
|
||||
static register_aspect_factory< composite_aspect<std::string>>
|
||||
passive_leader_shares_keep__composite_aspect_factory("passive_leader_shares_keep*composite_aspect");
|
||||
|
||||
static register_aspect_factory< composite_aspect<double>>
|
||||
|
@ -283,10 +283,10 @@ static register_aspect_factory< standard_aspect<std::string>>
|
|||
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<std::string>>
|
||||
passive_leader__standard_aspect_factory("passive_leader*standard_aspect");
|
||||
|
||||
static register_aspect_factory< standard_aspect<bool>>
|
||||
static register_aspect_factory< standard_aspect<std::string>>
|
||||
passive_leader_shares_keep__standard_aspect_factory("passive_leader_shares_keep*standard_aspect");
|
||||
|
||||
static register_aspect_factory< standard_aspect<double>>
|
||||
|
@ -358,10 +358,10 @@ static register_aspect_factory< standard_aspect<std::string>>
|
|||
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<std::string>>
|
||||
passive_leader__standard_aspect_factory2("passive_leader*");
|
||||
|
||||
static register_aspect_factory< standard_aspect<bool>>
|
||||
static register_aspect_factory< standard_aspect<std::string>>
|
||||
passive_leader_shares_keep__standard_aspect_factory2("passive_leader_shares_keep*");
|
||||
|
||||
static register_aspect_factory< standard_aspect<double>>
|
||||
|
@ -429,10 +429,10 @@ static register_lua_aspect_factory< lua_aspect<std::string>>
|
|||
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<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<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