diff --git a/src/whiteboard/recall.cpp b/src/whiteboard/recall.cpp index 3e00cc1a5c7..f8425b284fb 100644 --- a/src/whiteboard/recall.cpp +++ b/src/whiteboard/recall.cpp @@ -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; } diff --git a/src/whiteboard/recruit.cpp b/src/whiteboard/recruit.cpp index 2421725871c..75a85052529 100644 --- a/src/whiteboard/recruit.cpp +++ b/src/whiteboard/recruit.cpp @@ -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& 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()) { diff --git a/src/whiteboard/utility.cpp b/src/whiteboard/utility.cpp index 383d3a64028..081870fc421 100644 --- a/src/whiteboard/utility.cpp +++ b/src/whiteboard/utility.cpp @@ -89,6 +89,22 @@ unit* find_recruiter(std::size_t team_index, const map_location& hex) return nullptr; } +bool any_recruiter(int team_num, const map_location& loc, std::function 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(*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; diff --git a/src/whiteboard/utility.hpp b/src/whiteboard/utility.hpp index e43ba9ab0a4..ea6a6ee61e0 100644 --- a/src/whiteboard/utility.hpp +++ b/src/whiteboard/utility.hpp @@ -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(std::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 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