wb: fix handling of extra_recruit and [filter_recall]

fixes #3100
This commit is contained in:
gfgtdf 2018-05-20 03:30:02 +02:00
parent a24fa35c34
commit 491605dc97
4 changed files with 34 additions and 3 deletions

View file

@ -34,6 +34,7 @@
#include "statistics.hpp"
#include "synced_context.hpp"
#include "team.hpp"
#include "units/filter.hpp"
#include "units/unit.hpp"
#include "units/animation_component.hpp"
@ -233,7 +234,12 @@ action::error recall::check_validity() const
return NOT_ENOUGH_GOLD;
}
//Check that there is a leader available to recall this unit
if(!find_recruiter(team_index(),get_recall_hex())) {
bool has_recruiter = any_recruiter(team_index() - 1, get_recall_hex(), [&](unit& leader) {
const unit_filter ufilt(vconfig(leader.recall_filter()));
return ufilt(*temp_unit_, map_location::null_location());
});
if(!has_recruiter) {
return NO_LEADER;
}

View file

@ -207,10 +207,14 @@ action::error recruit::check_validity() const
return LOCATION_OCCUPIED;
}
//Check that unit to recruit is still in side's recruit list
//FIXME: look at leaders extra_recruit too.
const std::set<std::string>& recruits = resources::gameboard->teams()[team_index()].recruits();
if(recruits.find(unit_name_) == recruits.end()) {
return UNIT_UNAVAILABLE;
bool in_extra_recruit = any_recruiter(team_index() - 1, get_recruit_hex(), [&](unit& leader) {
return std::find(leader.recruits().begin(), leader.recruits().end(), unit_name_) != leader.recruits().end();
});
if (!in_extra_recruit) {
return UNIT_UNAVAILABLE;
}
}
//Check that there is still enough gold to recruit this unit
if(temp_unit_->cost() > resources::gameboard->teams()[team_index()].gold()) {

View file

@ -89,6 +89,22 @@ unit* find_recruiter(size_t team_index, const map_location& hex)
return nullptr;
}
bool any_recruiter(int team_num, const map_location& loc, std::function<bool(unit&)> func)
{
if ( !resources::gameboard->map().is_castle(loc) ) {
return false;
}
for(unit& u : resources::gameboard->units()) {
if(u.can_recruit() && u.side() == team_num && dynamic_cast<game_state&>(*resources::filter_con).can_recruit_on(u, loc)) {
if(func(u)) {
return true;
}
}
}
return false;
}
unit* future_visible_unit(map_location hex, int viewer_side)
{
future_map planned_unit_map;

View file

@ -53,6 +53,11 @@ unit_const_ptr find_backup_leader(const unit& leader);
* @retval nullptr if no such leader has been found
*/
unit* find_recruiter(size_t team_index, const map_location&);
/**
* executes @a func for each unti of side of @a side_num that can recruit on @a loc.
* @a func takes the leader unit and can return true to 'break' the loop
*/
bool any_recruiter(int side_num, const map_location& loc, std::function<bool(unit&)> func);
/// Applies the future unit map and @return a pointer to the unit at hex
/// @retval nullptr if none is visible to the specified viewer side