move unit_filter implementation out of unit
The purpose is to simplify the unit class, and perhaps allow for some optimizations regarding how unit filters are impemented.
This commit is contained in:
parent
4046666bee
commit
d803cde06a
22 changed files with 578 additions and 460 deletions
|
@ -1039,6 +1039,8 @@
|
|||
<Unit filename="..\..\src\unit_display.hpp" />
|
||||
<Unit filename="..\..\src\unit_drawer.cpp" />
|
||||
<Unit filename="..\..\src\unit_drawer.hpp" />
|
||||
<Unit filename="..\..\src\unit_filter.cpp" />
|
||||
<Unit filename="..\..\src\unit_filter.hpp" />
|
||||
<Unit filename="..\..\src\unit_formula_manager.cpp" />
|
||||
<Unit filename="..\..\src\unit_formula_manager.hpp" />
|
||||
<Unit filename="..\..\src\unit_frame.cpp" />
|
||||
|
|
|
@ -21192,6 +21192,14 @@
|
|||
RelativePath="..\..\src\unit_drawer.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\unit_filter.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\unit_filter.hpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\unit_formula_manager.cpp"
|
||||
>
|
||||
|
|
|
@ -897,6 +897,7 @@ set(wesnoth-main_SRC
|
|||
unit_animation_component.cpp
|
||||
unit_display.cpp
|
||||
unit_drawer.cpp
|
||||
unit_filter.cpp
|
||||
unit_formula_manager.cpp
|
||||
unit_frame.cpp
|
||||
unit_helper.cpp
|
||||
|
|
|
@ -529,6 +529,7 @@ wesnoth_sources = Split("""
|
|||
unit_animation_component.cpp
|
||||
unit_display.cpp
|
||||
unit_drawer.cpp
|
||||
unit_filter.cpp
|
||||
unit_formula_manager.cpp
|
||||
unit_frame.cpp
|
||||
unit_helper.cpp
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "../team.hpp"
|
||||
#include "../unit.hpp"
|
||||
#include "../unit_display.hpp"
|
||||
#include "../unit_filter.hpp"
|
||||
#include "../variable.hpp"
|
||||
#include "../whiteboard/manager.hpp"
|
||||
|
||||
|
@ -429,7 +430,11 @@ namespace { // Helpers for get_recalls()
|
|||
// Only units that match the leader's recall filter are valid.
|
||||
scoped_recall_unit this_unit("this_unit", save_id, leader_team.recall_list().find_index(recall_unit.id()));
|
||||
|
||||
if ( recall_unit.matches_filter(vconfig(leader->recall_filter()), map_location::null_location()) )
|
||||
const vconfig & rfilter = vconfig(leader->recall_filter());
|
||||
if ( unit_filter::matches_filter( rfilter,
|
||||
recall_unit,
|
||||
map_location::null_location(),
|
||||
resources::gameboard) )
|
||||
{
|
||||
result.push_back(recall_unit_ptr);
|
||||
if ( already_added != NULL )
|
||||
|
@ -527,8 +532,12 @@ namespace { // Helpers for check_recall_location()
|
|||
team& recall_team = (*resources::teams)[recaller.side()-1];
|
||||
scoped_recall_unit this_unit("this_unit", recall_team.save_id(),
|
||||
recall_team.recall_list().find_index(recall_unit.id()));
|
||||
if ( !recall_unit.matches_filter(vconfig(recaller.recall_filter()),
|
||||
map_location::null_location()) )
|
||||
|
||||
const vconfig & rfilter = vconfig(recaller.recall_filter());
|
||||
if ( !unit_filter::matches_filter(rfilter,
|
||||
recall_unit,
|
||||
map_location::null_location(),
|
||||
resources::gameboard) )
|
||||
return RECRUIT_NO_ABLE_LEADER;
|
||||
|
||||
// Make sure the unit is on a keep.
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "ai/lua/core.hpp"
|
||||
#include "ai/lua/lua_object.hpp"
|
||||
#include "ai/manager.hpp"
|
||||
#include "game_board.hpp"
|
||||
#include "log.hpp"
|
||||
#include "map_location.hpp"
|
||||
#include "resources.hpp"
|
||||
|
@ -32,6 +33,7 @@
|
|||
#include "terrain_filter.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_map.hpp"
|
||||
#include "unit_filter.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
@ -133,7 +135,7 @@ void target_unit_goal::add_targets(std::back_insert_iterator< std::vector< targe
|
|||
|
||||
//find the enemy leaders and explicit targets
|
||||
BOOST_FOREACH(const unit &u, *resources::units) {
|
||||
if (u.matches_filter(vconfig(criteria), u.get_location())) {
|
||||
if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::gameboard)) {
|
||||
LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value() << "\n";
|
||||
*target_list = target(u.get_location(), value(), target::EXPLICIT);
|
||||
}
|
||||
|
@ -262,7 +264,7 @@ void protect_goal::add_targets(std::back_insert_iterator< std::vector< target >
|
|||
continue;
|
||||
}
|
||||
//TODO: we will protect hidden units, by not testing for invisibility to current side
|
||||
if (u.matches_filter(vconfig(criteria), u.get_location())) {
|
||||
if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::gameboard)) {
|
||||
DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected\n";
|
||||
items.insert(u.get_location());
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "../../resources.hpp"
|
||||
#include "../../team.hpp"
|
||||
#include "../../tod_manager.hpp"
|
||||
#include "../../unit_filter.hpp"
|
||||
#include "../../unit_map.hpp"
|
||||
#include "../../unit_types.hpp"
|
||||
#include "../../util.hpp"
|
||||
|
@ -251,7 +252,7 @@ void recruitment::execute() {
|
|||
BOOST_FOREACH(const unit_const_ptr & recall, current_team().recall_list()) {
|
||||
// Check if this leader is allowed to recall this unit.
|
||||
vconfig filter = vconfig(leader->recall_filter());
|
||||
if (!recall->matches_filter(filter, map_location::null_location())) {
|
||||
if (!unit_filter::matches_filter(filter, *recall, map_location::null_location(), resources::gameboard)) {
|
||||
continue;
|
||||
}
|
||||
data.recruits.insert(recall->type_id());
|
||||
|
@ -476,7 +477,7 @@ const std::string* recruitment::get_appropriate_recall(const std::string& type,
|
|||
}
|
||||
// Check if this leader is allowed to recall this unit.
|
||||
vconfig filter = vconfig(leader_data.leader->recall_filter());
|
||||
if (!recall_unit->matches_filter(filter, map_location::null_location())) {
|
||||
if (!unit_filter::matches_filter(filter, *recall_unit, map_location::null_location(), resources::gameboard)) {
|
||||
LOG_AI_RECRUITMENT << "Refused recall because of filter: " << recall_unit->id() << "\n";
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../../resources.hpp"
|
||||
#include "../../unit.hpp"
|
||||
#include "../../pathfind/pathfind.hpp"
|
||||
#include "../../unit_filter.hpp"
|
||||
|
||||
namespace ai {
|
||||
|
||||
|
@ -75,7 +76,7 @@ boost::shared_ptr<attacks_vector> aspect_attacks::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->matches_filter(vconfig(filter_own_), i->get_location())) {
|
||||
if (!unit_filter::matches_filter(vconfig(filter_own_), *i, i->get_location(), resources::gameboard)) {
|
||||
continue;
|
||||
}
|
||||
unit_locs.push_back(i->get_location());
|
||||
|
@ -98,7 +99,7 @@ boost::shared_ptr<attacks_vector> aspect_attacks::analyze_targets() const
|
|||
if (current_team().is_enemy(j->side()) && !j->incapacitated() &&
|
||||
!j->invisible(j->get_location()))
|
||||
{
|
||||
if (!j->matches_filter(vconfig(filter_enemy_), j->get_location())) {
|
||||
if (!unit_filter::matches_filter(vconfig(filter_enemy_), *j, j->get_location(), resources::gameboard)) {
|
||||
continue;
|
||||
}
|
||||
map_location adjacent[6];
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
#include "../unit_animation_component.hpp"
|
||||
#include "../unit_display.hpp"
|
||||
#include "../unit_helper.hpp"
|
||||
#include "../unit_filter.hpp"
|
||||
#include "../wml_exception.hpp"
|
||||
|
||||
#include "../utils/foreach.tpp"
|
||||
|
@ -405,7 +406,7 @@ namespace { // Support functions
|
|||
speaker = units->find(event_info.loc2);
|
||||
} else if(speaker_str != "narrator") {
|
||||
for(speaker = units->begin(); speaker != units->end(); ++speaker){
|
||||
if ( speaker->matches_filter(cfg) )
|
||||
if ( unit_filter::matches_filter(cfg,*speaker, resources::gameboard) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -778,7 +779,7 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg)
|
|||
std::vector<unit*> healers;
|
||||
if (!healers_filter.null()) {
|
||||
BOOST_FOREACH(unit& u, *units) {
|
||||
if ( u.matches_filter(healers_filter) && u.has_ability_type("heals") ) {
|
||||
if ( unit_filter::matches_filter(healers_filter,u, resources::gameboard) && u.has_ability_type("heals") ) {
|
||||
healers.push_back(&u);
|
||||
}
|
||||
}
|
||||
|
@ -799,7 +800,7 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg)
|
|||
u = units->find(event_info.loc1);
|
||||
if(!u.valid()) return;
|
||||
}
|
||||
else if ( !u->matches_filter(healed_filter) ) continue;
|
||||
else if ( !unit_filter::matches_filter(healed_filter,*u, resources::gameboard) ) continue;
|
||||
|
||||
int heal_amount = u->max_hitpoints() - u->hitpoints();
|
||||
if(amount.blank() || amount == "full") u->set_hitpoints(u->max_hitpoints());
|
||||
|
@ -858,7 +859,7 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg)
|
|||
secondary_unit = false;
|
||||
for(unit_map::const_unit_iterator unit = resources::units->begin();
|
||||
unit != resources::units->end(); ++unit) {
|
||||
if ( unit->matches_filter(cfg.child("secondary_unit")) )
|
||||
if ( unit_filter::matches_filter(cfg.child("secondary_unit"), *unit, resources::gameboard) )
|
||||
{
|
||||
killer_loc = entity_location(*unit);
|
||||
secondary_unit = true;
|
||||
|
@ -873,7 +874,7 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg)
|
|||
//Find all the dead units first, because firing events ruins unit_map iteration
|
||||
std::vector<unit *> dead_men_walking;
|
||||
BOOST_FOREACH(unit & u, *resources::units){
|
||||
if ( u.matches_filter(cfg) ) {
|
||||
if ( unit_filter::matches_filter(cfg,u, resources::gameboard) ) {
|
||||
dead_men_walking.push_back(&u);
|
||||
}
|
||||
}
|
||||
|
@ -947,7 +948,7 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg)
|
|||
{
|
||||
for(std::vector<unit_ptr>::iterator j = pi->recall_list().begin(); j != pi->recall_list().end();) { //TODO: This block is really messy, cleanup somehow...
|
||||
scoped_recall_unit auto_store("this_unit", pi->save_id(), j - pi->recall_list().begin());
|
||||
if ((*j)->matches_filter(cfg, map_location())) {
|
||||
if (unit_filter::matches_filter(cfg, *(*j), map_location(), resources::gameboard)) {
|
||||
j = pi->recall_list().erase(j);
|
||||
} else {
|
||||
++j;
|
||||
|
@ -1415,7 +1416,7 @@ WML_HANDLER_FUNCTION(object, event_info, cfg)
|
|||
map_location loc;
|
||||
if(!filter.null()) {
|
||||
BOOST_FOREACH(const unit &u, *resources::units) {
|
||||
if ( u.matches_filter(filter) ) {
|
||||
if ( unit_filter::matches_filter(filter,u, resources::gameboard) ) {
|
||||
loc = u.get_location();
|
||||
break;
|
||||
}
|
||||
|
@ -1430,7 +1431,7 @@ WML_HANDLER_FUNCTION(object, event_info, cfg)
|
|||
|
||||
std::string command_type = "then";
|
||||
|
||||
if ( u != resources::units->end() && (filter.null() || u->matches_filter(filter)) )
|
||||
if ( u != resources::units->end() && (filter.null() || unit_filter::matches_filter(filter,*u, resources::gameboard)) )
|
||||
{
|
||||
///@deprecated This can be removed (and a proper duration=level implemented) after 1.11.2
|
||||
/// Don't forget to remove it from wmllint too!
|
||||
|
@ -1545,7 +1546,7 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg)
|
|||
for(std::vector<unit_ptr>::iterator u = avail.begin(); u != avail.end(); ++u) {
|
||||
DBG_NG << "checking unit against filter...\n";
|
||||
scoped_recall_unit auto_store("this_unit", player_id, u - avail.begin());
|
||||
if ((*u)->matches_filter(unit_filter, map_location())) {
|
||||
if (unit_filter::matches_filter(unit_filter, *(*u), map_location(), resources::gameboard)) {
|
||||
DBG_NG << (*u)->id() << " matched the filter...\n";
|
||||
const unit_ptr to_recruit = *u;
|
||||
const unit* pass_check = to_recruit.get();
|
||||
|
@ -1556,8 +1557,8 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg)
|
|||
BOOST_FOREACH(unit_map::const_unit_iterator leader, leaders) {
|
||||
DBG_NG << "...considering " + leader->id() + " as the recalling leader...\n";
|
||||
map_location loc = cfg_loc;
|
||||
if ( (leader_filter.null() || leader->matches_filter(leader_filter)) &&
|
||||
(*u)->matches_filter(vconfig(leader->recall_filter()), map_location()) ) {
|
||||
if ( (leader_filter.null() || unit_filter::matches_filter(leader_filter, *leader, resources::gameboard)) &&
|
||||
unit_filter::matches_filter(vconfig(leader->recall_filter()), *(*u),map_location(), resources::gameboard) ) {
|
||||
DBG_NG << "...matched the leader filter and is able to recall the unit.\n";
|
||||
if(!resources::gameboard->map().on_board(loc))
|
||||
loc = leader->get_location();
|
||||
|
@ -1725,7 +1726,7 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg)
|
|||
}
|
||||
unit_map::iterator itor;
|
||||
BOOST_FOREACH(unit &u, *resources::units) {
|
||||
if ( u.matches_filter(filter) ) {
|
||||
if ( unit_filter::matches_filter(filter,u, resources::gameboard) ) {
|
||||
u.set_role(cfg["role"]);
|
||||
found = true;
|
||||
break;
|
||||
|
@ -1762,7 +1763,7 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg)
|
|||
for(size_t i=0; i < pi->recall_list().size(); ++i) {
|
||||
unit_ptr u = pi->recall_list()[i];
|
||||
scoped_recall_unit auto_store("this_unit", player_id, i); //TODO: Should this not be inside the if? Explain me.
|
||||
if (u->matches_filter(filter, map_location())) {
|
||||
if (unit_filter::matches_filter(filter, *u, map_location(), resources::gameboard)) {
|
||||
u->set_role(cfg["role"]);
|
||||
found=true;
|
||||
break;
|
||||
|
@ -2286,7 +2287,7 @@ WML_HANDLER_FUNCTION(teleport, event_info, cfg)
|
|||
const vconfig & filter = cfg.child("filter");
|
||||
if(!filter.null()) {
|
||||
for (u = resources::units->begin(); u != resources::units->end(); ++u){
|
||||
if ( u->matches_filter(filter) )
|
||||
if ( unit_filter::matches_filter(filter,*u, resources::gameboard) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "conditional_wml.hpp"
|
||||
|
||||
#include "../config.hpp"
|
||||
#include "../game_board.hpp"
|
||||
#include "../game_data.hpp"
|
||||
#include "../log.hpp"
|
||||
#include "../recall_list_manager.hpp"
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include "../team.hpp"
|
||||
#include "../terrain_filter.hpp"
|
||||
#include "../unit.hpp"
|
||||
#include "../unit_filter.hpp"
|
||||
#include "../unit_map.hpp"
|
||||
#include "../unit_types.hpp"
|
||||
#include "../util.hpp"
|
||||
|
@ -74,7 +76,7 @@ namespace { // Support functions
|
|||
int match_count = 0;
|
||||
BOOST_FOREACH(const unit &i, *resources::units)
|
||||
{
|
||||
if ( i.hitpoints() > 0 && i.matches_filter(*u) ) {
|
||||
if ( i.hitpoints() > 0 && unit_filter::matches_filter(*u,i, resources::gameboard) ) {
|
||||
++match_count;
|
||||
if(counts == default_counts) {
|
||||
// by default a single match is enough, so avoid extra work
|
||||
|
@ -95,7 +97,7 @@ namespace { // Support functions
|
|||
break;
|
||||
}
|
||||
scoped_recall_unit auto_store("this_unit", team->save_id(), t);
|
||||
if ( team->recall_list()[t]->matches_filter(*u) ) {
|
||||
if ( unit_filter::matches_filter(*u,*team->recall_list()[t], resources::gameboard) ) {
|
||||
++match_count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
#include "global.hpp"
|
||||
#include "entity_location.hpp"
|
||||
|
||||
#include "../game_board.hpp"
|
||||
#include "../resources.hpp"
|
||||
#include "../unit.hpp"
|
||||
#include "../unit_filter.hpp"
|
||||
#include "../variable.hpp"
|
||||
|
||||
|
||||
|
@ -98,7 +101,7 @@ bool entity_location::matches_unit_filter(const unit_map::const_iterator & un_it
|
|||
|
||||
// Filter the unit at the filter location (should be the unit's
|
||||
// location if no special filter location was specified).
|
||||
return un_it->matches_filter(filter, filter_loc_) &&
|
||||
return unit_filter::matches_filter(filter, *un_it, filter_loc_, resources::gameboard) &&
|
||||
matches_unit(un_it);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,12 +13,14 @@
|
|||
|
||||
#include "pathfind/teleport.hpp"
|
||||
|
||||
#include "game_board.hpp"
|
||||
#include "log.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "team.hpp"
|
||||
#include "terrain_filter.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_filter.hpp"
|
||||
#include "unit_map.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -74,7 +76,7 @@ void teleport_group::get_teleport_pair(
|
|||
vconfig filter(cfg_.child_or_empty("filter"), true);
|
||||
vconfig source(cfg_.child_or_empty("source"), true);
|
||||
vconfig target(cfg_.child_or_empty("target"), true);
|
||||
if (u.matches_filter(filter, loc)) {
|
||||
if (unit_filter::matches_filter(filter, u, loc, resources::gameboard)) {
|
||||
|
||||
scoped_xy_unit teleport_unit("teleport_unit", loc.x, loc.y, *resources::units);
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@
|
|||
#include "tstring.hpp" // for t_string, operator+
|
||||
#include "unit.hpp" // for unit, intrusive_ptr_add_ref, etc
|
||||
#include "unit_animation_component.hpp" // for unit_animation_component
|
||||
#include "unit_filter.hpp"
|
||||
#include "unit_map.hpp" // for unit_map, etc
|
||||
#include "unit_ptr.hpp" // for unit_const_ptr, unit_ptr
|
||||
#include "unit_types.hpp" // for unit_type_data, unit_types, etc
|
||||
|
@ -857,7 +858,7 @@ static int intf_get_units(lua_State *L)
|
|||
for (unit_map::const_unit_iterator ui = units.begin(), ui_end = units.end();
|
||||
ui != ui_end; ++ui)
|
||||
{
|
||||
if (!filter.null() && !ui->matches_filter(filter, ui->get_location()))
|
||||
if (!filter.null() && !unit_filter::matches_filter(filter, *ui, ui->get_location(), resources::gameboard))
|
||||
continue;
|
||||
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id());
|
||||
lua_pushvalue(L, 1);
|
||||
|
@ -894,11 +895,11 @@ static int intf_match_unit(lua_State *L)
|
|||
team &t = (*resources::teams)[side - 1];
|
||||
scoped_recall_unit auto_store("this_unit",
|
||||
t.save_id(), t.recall_list().find_index(u->id()));
|
||||
lua_pushboolean(L, u->matches_filter(filter, map_location()));
|
||||
lua_pushboolean(L, unit_filter::matches_filter(filter, *u, map_location(), resources::gameboard));
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_pushboolean(L, u->matches_filter(filter, u->get_location()));
|
||||
lua_pushboolean(L, unit_filter::matches_filter(filter, *u, u->get_location(), resources::gameboard));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -927,7 +928,7 @@ static int intf_get_recall_units(lua_State *L)
|
|||
if (!filter.null()) {
|
||||
scoped_recall_unit auto_store("this_unit",
|
||||
t.save_id(), t.recall_list().find_index(u->id()));
|
||||
if (!u->matches_filter(filter, map_location()))
|
||||
if (!unit_filter::matches_filter(filter, *u, map_location(), resources::gameboard))
|
||||
continue;
|
||||
}
|
||||
new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(s, u->underlying_id());
|
||||
|
@ -2002,7 +2003,7 @@ static int intf_find_cost_map(lua_State *L)
|
|||
ui != ui_end; ++ui)
|
||||
{
|
||||
bool on_map = ui->get_location().valid();
|
||||
if (on_map && ui->matches_filter(filter, ui->get_location()))
|
||||
if (on_map && unit_filter::matches_filter(filter, *ui,ui->get_location(), resources::gameboard))
|
||||
{
|
||||
real_units. push_back(&(*ui));
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "global.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
#include "game_board.hpp"
|
||||
#include "log.hpp"
|
||||
#include "recall_list_manager.hpp"
|
||||
#include "resources.hpp"
|
||||
|
@ -26,6 +27,7 @@
|
|||
#include "serialization/string_utils.hpp"
|
||||
#include "network.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_filter.hpp"
|
||||
#include "unit_map.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -134,7 +136,7 @@ bool side_filter::match_internal(const team &t) const
|
|||
if (u.side() != t.side()) {
|
||||
continue;
|
||||
}
|
||||
if (u.matches_filter(unit_filter, u.get_location(), flat_)) {
|
||||
if (unit_filter::matches_filter(unit_filter, u, u.get_location(), resources::gameboard, flat_)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -142,7 +144,7 @@ bool side_filter::match_internal(const team &t) const
|
|||
if(!found && unit_filter["search_recall_list"].to_bool(false)) {
|
||||
BOOST_FOREACH(const unit_const_ptr & u, t.recall_list()) {
|
||||
scoped_recall_unit this_unit("this_unit", t.save_id(),t.recall_list().find_index(u->id()));
|
||||
if(u->matches_filter(unit_filter, u->get_location(), flat_)) {
|
||||
if(unit_filter::matches_filter(unit_filter, *u, u->get_location(), resources::gameboard, flat_)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "terrain_filter.hpp"
|
||||
#include "tod_manager.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_filter.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -153,7 +154,7 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x
|
|||
if(cfg_.has_child("filter")) {
|
||||
const vconfig& unit_filter = cfg_.child("filter");
|
||||
const unit_map::const_iterator u = units_.find(loc);
|
||||
if (u == units_.end() || !u->matches_filter(unit_filter, loc, flat_))
|
||||
if (u == units_.end() || !unit_filter::matches_filter(unit_filter, *u, loc, resources::gameboard, flat_))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
408
src/unit.cpp
408
src/unit.cpp
|
@ -39,6 +39,7 @@
|
|||
#include "unit_abilities.hpp" // for effect, filter_base_matches
|
||||
#include "unit_animation.hpp" // for unit_animation
|
||||
#include "unit_animation_component.hpp" // for unit_animation_component
|
||||
#include "unit_filter.hpp"
|
||||
#include "unit_formula_manager.hpp" // for unit_formula_manager
|
||||
#include "unit_id.hpp"
|
||||
#include "unit_map.hpp" // for unit_map, etc
|
||||
|
@ -1272,411 +1273,6 @@ void unit::remove_ability_by_id(const std::string &ability)
|
|||
}
|
||||
}
|
||||
|
||||
bool unit::matches_filter(const vconfig& cfg, const map_location& loc, bool use_flat_tod) const
|
||||
{
|
||||
bool matches = true;
|
||||
|
||||
if(loc.valid()) {
|
||||
assert(resources::units != NULL);
|
||||
scoped_xy_unit auto_store("this_unit", loc.x, loc.y, *resources::units);
|
||||
matches = internal_matches_filter(cfg, loc, use_flat_tod);
|
||||
} else {
|
||||
// If loc is invalid, then this is a recall list unit (already been scoped)
|
||||
matches = internal_matches_filter(cfg, loc, use_flat_tod);
|
||||
}
|
||||
|
||||
// Handle [and], [or], and [not] with in-order precedence
|
||||
vconfig::all_children_iterator cond = cfg.ordered_begin();
|
||||
vconfig::all_children_iterator cond_end = cfg.ordered_end();
|
||||
while(cond != cond_end)
|
||||
{
|
||||
|
||||
const std::string& cond_name = cond.get_key();
|
||||
const vconfig& cond_filter = cond.get_child();
|
||||
|
||||
// Handle [and]
|
||||
if(cond_name == "and") {
|
||||
matches = matches && matches_filter(cond_filter,loc,use_flat_tod);
|
||||
}
|
||||
// Handle [or]
|
||||
else if(cond_name == "or") {
|
||||
matches = matches || matches_filter(cond_filter,loc,use_flat_tod);
|
||||
}
|
||||
// Handle [not]
|
||||
else if(cond_name == "not") {
|
||||
matches = matches && !matches_filter(cond_filter,loc,use_flat_tod);
|
||||
}
|
||||
|
||||
++cond;
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
bool unit::internal_matches_filter(const vconfig& cfg, const map_location& loc, bool use_flat_tod) const
|
||||
{
|
||||
config::attribute_value cfg_name = cfg["name"];
|
||||
if (!cfg_name.blank() && cfg_name.str() != name_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const config::attribute_value cfg_id = cfg["id"];
|
||||
if (!cfg_id.blank()) {
|
||||
const std::string& id = cfg_id;
|
||||
const std::string& this_id = this->id();
|
||||
|
||||
if (id == this_id) {
|
||||
}
|
||||
else if ( id.find(',') == std::string::npos ){
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
const std::vector<std::string>& ids = utils::split(id);
|
||||
if (std::find(ids.begin(), ids.end(), this_id) == ids.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow 'speaker' as an alternative to id, since people use it so often
|
||||
config::attribute_value cfg_speaker = cfg["speaker"];
|
||||
if (!cfg_speaker.blank() && cfg_speaker.str() != id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(cfg.has_child("filter_location")) {
|
||||
assert(resources::gameboard != NULL);
|
||||
assert(resources::teams != NULL);
|
||||
assert(resources::tod_manager != NULL);
|
||||
assert(resources::units != NULL);
|
||||
const vconfig& t_cfg = cfg.child("filter_location");
|
||||
terrain_filter t_filter(t_cfg, *resources::units, use_flat_tod);
|
||||
if(!t_filter.match(loc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const vconfig& filter_side = cfg.child("filter_side");
|
||||
if(!filter_side.null()) {
|
||||
side_filter s_filter(filter_side);
|
||||
if(!s_filter.match(this->side()))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Also allow filtering on location ranges outside of the location filter
|
||||
config::attribute_value cfg_x = cfg["x"];
|
||||
config::attribute_value cfg_y = cfg["y"];
|
||||
if (!cfg_x.blank() || !cfg_y.blank()){
|
||||
if(cfg_x == "recall" && cfg_y == "recall") {
|
||||
//locations on the map are considered to not be on a recall list
|
||||
if ((!resources::gameboard && loc.valid()) ||
|
||||
(resources::gameboard && resources::gameboard->map().on_board(loc)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if(cfg_x.empty() && cfg_y.empty()) {
|
||||
return false;
|
||||
} else if(!loc.matches_range(cfg_x, cfg_y)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The type could be a comma separated list of types
|
||||
config::attribute_value cfg_type = cfg["type"];
|
||||
if (!cfg_type.blank())
|
||||
{
|
||||
const std::string type_ids = cfg_type.str();
|
||||
const std::string& this_type = type_id();
|
||||
|
||||
// We only do the full CSV search if we find a comma in there,
|
||||
// and if the subsequence is found within the main sequence.
|
||||
// This is because doing the full CSV split is expensive.
|
||||
if ( type_ids == this_type ) {
|
||||
// pass
|
||||
} else if ( type_ids.find(',') != std::string::npos &&
|
||||
type_ids.find(this_type) != std::string::npos ) {
|
||||
const std::vector<std::string>& vals = utils::split(type_ids);
|
||||
|
||||
if(std::find(vals.begin(),vals.end(),this_type) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The variation_type could be a comma separated list of types
|
||||
config::attribute_value cfg_variation_type = cfg["variation"];
|
||||
if (!cfg_variation_type.blank())
|
||||
{
|
||||
const std::string type_ids = cfg_variation_type.str();
|
||||
const std::string& this_type = variation_;
|
||||
|
||||
// We only do the full CSV search if we find a comma in there,
|
||||
// and if the subsequence is found within the main sequence.
|
||||
// This is because doing the full CSV split is expensive.
|
||||
if ( type_ids == this_type ) {
|
||||
// pass
|
||||
} else if ( type_ids.find(',') != std::string::npos &&
|
||||
type_ids.find(this_type) != std::string::npos ) {
|
||||
const std::vector<std::string>& vals = utils::split(type_ids);
|
||||
|
||||
if(std::find(vals.begin(),vals.end(),this_type) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The has_variation_type could be a comma separated list of types
|
||||
config::attribute_value cfg_has_variation_type = cfg["has_variation"];
|
||||
if (!cfg_has_variation_type.blank())
|
||||
{
|
||||
const std::string& var_ids = cfg_has_variation_type.str();
|
||||
const std::string& this_var = variation_;
|
||||
|
||||
if ( var_ids == this_var ) {
|
||||
// pass
|
||||
} else {
|
||||
|
||||
bool match = false;
|
||||
const std::vector<std::string>& variation_types = utils::split(var_ids);
|
||||
// If this unit is a variation itself then search in the base unit's variations.
|
||||
const unit_type* const type = this_var.empty() ? type_ : unit_types.find(type_->base_id());
|
||||
assert(type);
|
||||
|
||||
BOOST_FOREACH(const std::string& variation_id, variation_types) {
|
||||
if (type->has_variation(variation_id)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_ability = cfg["ability"];
|
||||
if (!cfg_ability.blank())
|
||||
{
|
||||
std::string ability = cfg_ability;
|
||||
if(has_ability_by_id(ability)) {
|
||||
// pass
|
||||
} else if ( ability.find(',') != std::string::npos ) {
|
||||
const std::vector<std::string>& vals = utils::split(ability);
|
||||
bool has_ability = false;
|
||||
for(std::vector<std::string>::const_iterator this_ability = vals.begin(); this_ability != vals.end(); ++this_ability) {
|
||||
if(has_ability_by_id(*this_ability)) {
|
||||
has_ability = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!has_ability) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_race = cfg["race"];
|
||||
if (!cfg_race.blank()) {
|
||||
std::string race = cfg_race;
|
||||
|
||||
if(race != race_->id()) {
|
||||
const std::vector<std::string>& vals = utils::split(race);
|
||||
if(std::find(vals.begin(), vals.end(), race_->id()) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_gender = cfg["gender"];
|
||||
if (!cfg_gender.blank() && string_gender(cfg_gender) != gender()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_side = cfg["side"];
|
||||
if (!cfg_side.blank() && cfg_side.to_int() != side()) {
|
||||
std::string side = cfg_side;
|
||||
if ( side.find(',') == std::string::npos ) {
|
||||
return false;
|
||||
}
|
||||
std::vector<std::string> vals = utils::split(side);
|
||||
if (std::find(vals.begin(), vals.end(), str_cast(side_)) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_has_weapon = cfg["has_weapon"];
|
||||
if (!cfg_has_weapon.blank()) {
|
||||
std::string weapon = cfg_has_weapon;
|
||||
bool has_weapon = false;
|
||||
const std::vector<attack_type>& attacks = this->attacks();
|
||||
for(std::vector<attack_type>::const_iterator i = attacks.begin();
|
||||
i != attacks.end(); ++i) {
|
||||
if(i->id() == weapon) {
|
||||
has_weapon = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!has_weapon) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_role = cfg["role"];
|
||||
if (!cfg_role.blank() && cfg_role.str() != role_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_ai_special = cfg["ai_special"];
|
||||
if (!cfg_ai_special.blank() && ((cfg_ai_special.str() == "guardian") != get_state(STATE_GUARDIAN))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_canrecruit = cfg["canrecruit"];
|
||||
if (!cfg_canrecruit.blank() && cfg_canrecruit.to_bool() != can_recruit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_recall_cost = cfg["recall_cost"];
|
||||
if (!cfg_recall_cost.blank() && cfg_recall_cost.to_int(-1) != recall_cost_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_level = cfg["level"];
|
||||
if (!cfg_level.blank() && cfg_level.to_int(-1) != level_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_defense = cfg["defense"];
|
||||
if (!cfg_defense.blank() && cfg_defense.to_int(-1) != defense_modifier(resources::gameboard->map().get_terrain(loc))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_movement = cfg["movement_cost"];
|
||||
if (!cfg_movement.blank() && cfg_movement.to_int(-1) != movement_cost(resources::gameboard->map().get_terrain(loc))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now start with the new WML based comparison.
|
||||
// If a key is in the unit and in the filter, they should match
|
||||
// filter only => not for us
|
||||
// unit only => not filtered
|
||||
const vconfig::child_list& wmlcfgs = cfg.get_children("filter_wml");
|
||||
if (!wmlcfgs.empty()) {
|
||||
config unit_cfg;
|
||||
for (unsigned i = 0; i < wmlcfgs.size(); ++i)
|
||||
{
|
||||
config fwml = wmlcfgs[i].get_parsed_config();
|
||||
/* Check if the filter only cares about variables.
|
||||
If so, no need to serialize the whole unit. */
|
||||
config::const_attr_itors ai = fwml.attribute_range();
|
||||
config::all_children_itors ci = fwml.all_children_range();
|
||||
if (std::distance(ai.first, ai.second) == 0 &&
|
||||
std::distance(ci.first, ci.second) == 1 &&
|
||||
ci.first->key == "variables") {
|
||||
if (!variables_.matches(ci.first->cfg))
|
||||
return false;
|
||||
} else {
|
||||
if (unit_cfg.empty())
|
||||
write(unit_cfg);
|
||||
if (!unit_cfg.matches(fwml))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.has_child("filter_vision")) {
|
||||
const vconfig::child_list& vis_filt = cfg.get_children("filter_vision");
|
||||
vconfig::child_list::const_iterator i, i_end = vis_filt.end();
|
||||
for (i = vis_filt.begin(); i != i_end; ++i) {
|
||||
bool visible = (*i)["visible"].to_bool(true);
|
||||
std::set<int> viewers;
|
||||
// Use standard side filter
|
||||
side_filter ssf(*i);
|
||||
std::vector<int> sides = ssf.get_teams();
|
||||
viewers.insert(sides.begin(), sides.end());
|
||||
if (viewers.empty()) {
|
||||
return false;
|
||||
}
|
||||
std::set<int>::const_iterator viewer, viewer_end = viewers.end();
|
||||
for (viewer = viewers.begin(); viewer != viewer_end; ++viewer) {
|
||||
bool fogged = teams_manager::get_teams()[*viewer - 1].fogged(loc);
|
||||
bool hiding = this->invisible(loc/*, false(?) */);
|
||||
bool unit_hidden = fogged || hiding;
|
||||
if (visible == unit_hidden) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.has_child("filter_adjacent")) {
|
||||
assert(resources::units && resources::gameboard);
|
||||
const unit_map& units = *resources::units;
|
||||
map_location adjacent[6];
|
||||
get_adjacent_tiles(loc, adjacent);
|
||||
vconfig::child_list::const_iterator i, i_end;
|
||||
const vconfig::child_list& adj_filt = cfg.get_children("filter_adjacent");
|
||||
for (i = adj_filt.begin(), i_end = adj_filt.end(); i != i_end; ++i) {
|
||||
int match_count=0;
|
||||
config::attribute_value i_adjacent = (*i)["adjacent"];
|
||||
std::vector<map_location::DIRECTION> dirs = !i_adjacent.blank() ?
|
||||
map_location::parse_directions(i_adjacent) : map_location::default_dirs();
|
||||
std::vector<map_location::DIRECTION>::const_iterator j, j_end = dirs.end();
|
||||
for (j = dirs.begin(); j != j_end; ++j) {
|
||||
unit_map::const_iterator unit_itor = units.find(adjacent[*j]);
|
||||
if (unit_itor == units.end()
|
||||
|| !unit_itor->matches_filter(*i, unit_itor->get_location(), use_flat_tod)) {
|
||||
continue;
|
||||
}
|
||||
config::attribute_value i_is_enemy = (*i)["is_enemy"];
|
||||
if (i_is_enemy.blank() || i_is_enemy.to_bool() ==
|
||||
teams_manager::get_teams()[this->side() - 1].is_enemy(unit_itor->side())) {
|
||||
++match_count;
|
||||
}
|
||||
}
|
||||
static std::vector<std::pair<int,int> > default_counts = utils::parse_ranges("1-6");
|
||||
config::attribute_value i_count = (*i)["count"];
|
||||
std::vector<std::pair<int,int> > counts = !i_count.blank()
|
||||
? utils::parse_ranges(i_count) : default_counts;
|
||||
if(!in_ranges(match_count, counts)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_find_in = cfg["find_in"];
|
||||
if (!cfg_find_in.blank()) {
|
||||
// Allow filtering by searching a stored variable of units
|
||||
variable_info vi(cfg_find_in, false, variable_info::TYPE_CONTAINER);
|
||||
if(!vi.is_valid) return false;
|
||||
if(vi.explicit_index) {
|
||||
config::const_child_iterator i = vi.vars->child_range(vi.key).first;
|
||||
std::advance(i, vi.index);
|
||||
if ((*i)["id"] != id_) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!vi.vars->find_child(vi.key, "id", id_))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
config::attribute_value cfg_formula = cfg["formula"];
|
||||
if (!cfg_formula.blank()) {
|
||||
if (!formula_man_->matches_filter(cfg_formula, loc, *this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_lua_function = cfg["lua_function"];
|
||||
if (!cfg_lua_function.blank()) {
|
||||
bool b = resources::lua_kernel->run_filter(cfg_lua_function.str().c_str(), *this);
|
||||
if (!b) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void unit::write(config& cfg) const
|
||||
{
|
||||
cfg.append(cfg_);
|
||||
|
@ -1984,7 +1580,7 @@ void unit::add_modification(const std::string& mod_type, const config& mod, bool
|
|||
{
|
||||
// Apply SUF.
|
||||
if (const config &afilter = effect.child("filter"))
|
||||
if (!matches_filter(vconfig(afilter), loc_)) continue;
|
||||
if (!unit_filter::matches_filter(vconfig(afilter), *this, loc_, resources::gameboard)) continue;
|
||||
|
||||
const std::string &apply_to = effect["apply_to"];
|
||||
const std::string &apply_times = effect["times"];
|
||||
|
|
13
src/unit.hpp
13
src/unit.hpp
|
@ -137,6 +137,7 @@ public:
|
|||
/** The unit type name */
|
||||
const t_string& type_name() const {return type_name_;}
|
||||
const std::string& undead_variation() const {return undead_variation_;}
|
||||
const std::string variation() const {return variation_; }
|
||||
|
||||
/** The unit name for display */
|
||||
const t_string &name() const { return name_; }
|
||||
|
@ -241,12 +242,6 @@ public:
|
|||
bool emits_zoc() const { return emit_zoc_ && !incapacitated();}
|
||||
bool matches_id(const std::string& unit_id) const;
|
||||
/* cfg: standard unit filter */
|
||||
bool matches_filter(const vconfig& cfg,const map_location& loc,bool use_flat_tod=false) const;
|
||||
/// Determine if *this matches @a filter at its current location.
|
||||
/// (Only use for units currently on the map; otherwise use the overload
|
||||
/// that takes a location, possibly with a null location.)
|
||||
bool matches_filter(const vconfig& filter, bool use_flat_tod=false) const
|
||||
{ return matches_filter(filter, get_location(), use_flat_tod); }
|
||||
const std::vector<std::string>& overlays() const { return overlays_; }
|
||||
|
||||
void write(config& cfg) const;
|
||||
|
@ -382,9 +377,6 @@ protected:
|
|||
private:
|
||||
void advance_to(const config &old_cfg, const unit_type &t,
|
||||
bool use_traits);
|
||||
|
||||
bool internal_matches_filter(const vconfig& cfg,const map_location& loc,
|
||||
bool use_flat_tod) const;
|
||||
/*
|
||||
* cfg: an ability WML structure
|
||||
*/
|
||||
|
@ -393,7 +385,10 @@ private:
|
|||
bool ability_affects_self(const std::string& ability,const config& cfg,const map_location& loc) const;
|
||||
bool resistance_filter_matches(const config& cfg,bool attacker,const std::string& damage_name, int res) const;
|
||||
|
||||
public:
|
||||
bool has_ability_by_id(const std::string& ability) const;
|
||||
// ^ Needed for unit_filter
|
||||
private:
|
||||
void remove_ability_by_id(const std::string& ability);
|
||||
|
||||
/** register a trait's name and its description for UI's use*/
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
* Manage unit-abilities, like heal, cure, and weapon_specials.
|
||||
*/
|
||||
|
||||
#include "game_board.hpp"
|
||||
#include "log.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "team.hpp"
|
||||
#include "terrain_filter.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_abilities.hpp"
|
||||
#include "unit_filter.hpp"
|
||||
#include "unit_map.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -295,7 +297,7 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map
|
|||
assert(resources::units && resources::gameboard && resources::teams && resources::tod_manager);
|
||||
|
||||
if (const config &afilter = cfg.child("filter"))
|
||||
if ( !matches_filter(vconfig(afilter), loc, illuminates) )
|
||||
if ( !unit_filter::matches_filter(vconfig(afilter), *this, loc, resources::gameboard, illuminates) )
|
||||
return false;
|
||||
|
||||
map_location adjacent[6];
|
||||
|
@ -313,7 +315,7 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map
|
|||
unit_map::const_iterator unit = units.find(adjacent[index]);
|
||||
if (unit == units.end())
|
||||
return false;
|
||||
if (!unit->matches_filter(vconfig(i), unit->get_location(), illuminates))
|
||||
if (!unit_filter::matches_filter(vconfig(i), *unit, unit->get_location(), resources::gameboard, illuminates))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -351,7 +353,7 @@ bool unit::ability_affects_adjacent(const std::string& ability, const config& cf
|
|||
std::vector<std::string> dirs = utils::split(i["adjacent"]);
|
||||
if(std::find(dirs.begin(),dirs.end(),adjacent_names[dir]) != dirs.end()) {
|
||||
if (const config &filter = i.child("filter")) {
|
||||
if ( matches_filter(vconfig(filter), loc, illuminates) )
|
||||
if ( unit_filter::matches_filter(vconfig(filter), *this, loc, resources::gameboard, illuminates) )
|
||||
return true;
|
||||
} else
|
||||
return true;
|
||||
|
@ -369,7 +371,7 @@ bool unit::ability_affects_self(const std::string& ability,const config& cfg,con
|
|||
const config &filter = cfg.child("filter_self");
|
||||
bool affect_self = cfg["affect_self"].to_bool(true);
|
||||
if (!filter || !affect_self) return affect_self;
|
||||
return matches_filter(vconfig(filter), loc, ability == "illuminates");
|
||||
return unit_filter::matches_filter(vconfig(filter), *this, loc, resources::gameboard, ability == "illuminates");
|
||||
}
|
||||
|
||||
bool unit::has_ability_type(const std::string& ability) const
|
||||
|
@ -792,7 +794,7 @@ namespace { // Helpers for attack_type::special_active()
|
|||
return true;
|
||||
|
||||
// Check for a unit match.
|
||||
if ( !un_it.valid() || !un_it->matches_filter(vconfig(filter_child), loc) )
|
||||
if ( !un_it.valid() || !unit_filter::matches_filter(vconfig(filter_child), *un_it, loc, resources::gameboard) )
|
||||
return false;
|
||||
|
||||
// Check for a weapon match.
|
||||
|
@ -882,7 +884,7 @@ bool attack_type::special_active(const config& special, AFFECTS whom,
|
|||
continue;
|
||||
unit_map::const_iterator unit = units.find(adjacent[index]);
|
||||
if ( unit == units.end() ||
|
||||
!unit->matches_filter(vconfig(i), adjacent[index]) )
|
||||
!unit_filter::matches_filter(vconfig(i), *unit, adjacent[index], resources::gameboard) )
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "resources.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_animation_component.hpp"
|
||||
#include "unit_filter.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -368,7 +369,7 @@ unit_animation::unit_animation(const config& cfg,const std::string& frame_string
|
|||
|
||||
}
|
||||
|
||||
int unit_animation::matches(const display &disp,const map_location& loc,const map_location& second_loc, const unit* my_unit,const std::string & event,const int value,hit_type hit,const attack_type* attack,const attack_type* second_attack, int value2) const
|
||||
int unit_animation::matches(const display &disp, const map_location& loc,const map_location& second_loc, const unit* my_unit,const std::string & event,const int value,hit_type hit,const attack_type* attack,const attack_type* second_attack, int value2) const
|
||||
{
|
||||
int result = base_score_;
|
||||
if(!event.empty()&&!event_.empty()) {
|
||||
|
@ -403,7 +404,7 @@ int unit_animation::matches(const display &disp,const map_location& loc,const ma
|
|||
}
|
||||
std::vector<config>::const_iterator myitor;
|
||||
for(myitor = unit_filter_.begin(); myitor != unit_filter_.end(); ++myitor) {
|
||||
if (!my_unit->matches_filter(vconfig(*myitor), loc)) return MATCH_FAIL;
|
||||
if (!unit_filter::matches_filter(vconfig(*myitor), *my_unit, loc, &disp.get_disp_context())) return MATCH_FAIL;
|
||||
++result;
|
||||
}
|
||||
if(!secondary_unit_filter_.empty()) {
|
||||
|
@ -412,7 +413,7 @@ int unit_animation::matches(const display &disp,const map_location& loc,const ma
|
|||
if (unit->get_location() == second_loc) {
|
||||
std::vector<config>::const_iterator second_itor;
|
||||
for(second_itor = secondary_unit_filter_.begin(); second_itor != secondary_unit_filter_.end(); ++second_itor) {
|
||||
if (!unit->matches_filter(vconfig(*second_itor), second_loc)) return MATCH_FAIL;
|
||||
if (!unit_filter::matches_filter(vconfig(*second_itor), *unit, second_loc, &disp.get_disp_context())) return MATCH_FAIL;
|
||||
result++;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "terrain_filter.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_animation_component.hpp"
|
||||
#include "unit_filter.hpp"
|
||||
#include "unit_map.hpp"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
@ -773,7 +774,7 @@ void wml_animation_internal(unit_animator &animator, const vconfig &cfg, const m
|
|||
vconfig filter = cfg.child("filter");
|
||||
if(!filter.null()) {
|
||||
for (u = resources::units->begin(); u != resources::units->end(); ++u) {
|
||||
if ( u->matches_filter(filter) )
|
||||
if ( unit_filter::matches_filter(filter, *u, resources::gameboard) )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
447
src/unit_filter.cpp
Normal file
447
src/unit_filter.cpp
Normal file
|
@ -0,0 +1,447 @@
|
|||
/*
|
||||
Copyright (C) 2014 by Chris Beck <render787@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "unit_filter.hpp"
|
||||
#include "global.hpp"
|
||||
|
||||
#include "config.hpp"
|
||||
#include "display_context.hpp"
|
||||
#include "map_location.hpp"
|
||||
#include "resources.hpp" //Needed for lua kernel pointer
|
||||
#include "scripting/lua.hpp" //Needed for lua kernel
|
||||
#include "side_filter.hpp"
|
||||
#include "team.hpp"
|
||||
#include "terrain_filter.hpp"
|
||||
#include "unit.hpp"
|
||||
#include "unit_formula_manager.hpp"
|
||||
#include "unit_map.hpp"
|
||||
#include "unit_types.hpp"
|
||||
#include "variable.hpp" // needed for vconfig, scoped unit
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace { bool internal_matches_filter(const vconfig& filter, const unit & u, const map_location& loc, const display_context * board, bool use_flat_tod); }
|
||||
|
||||
namespace unit_filter {
|
||||
|
||||
bool matches_filter(const vconfig& filter, const unit & u, const display_context * board, bool use_flat_tod)
|
||||
{ return matches_filter(filter, u, u.get_location(), board, use_flat_tod); }
|
||||
|
||||
bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, const display_context * board, bool use_flat_tod)
|
||||
{
|
||||
bool matches = true;
|
||||
|
||||
if(loc.valid()) {
|
||||
assert(board != NULL);
|
||||
scoped_xy_unit auto_store("this_unit", loc.x, loc.y, board->units());
|
||||
matches = internal_matches_filter(cfg, u, loc, board, use_flat_tod);
|
||||
} else {
|
||||
// If loc is invalid, then this is a recall list unit (already been scoped)
|
||||
matches = internal_matches_filter(cfg, u, loc, board, use_flat_tod);
|
||||
}
|
||||
|
||||
// Handle [and], [or], and [not] with in-order precedence
|
||||
vconfig::all_children_iterator cond = cfg.ordered_begin();
|
||||
vconfig::all_children_iterator cond_end = cfg.ordered_end();
|
||||
while(cond != cond_end)
|
||||
{
|
||||
|
||||
const std::string& cond_name = cond.get_key();
|
||||
const vconfig& cond_filter = cond.get_child();
|
||||
|
||||
// Handle [and]
|
||||
if(cond_name == "and") {
|
||||
matches = matches && matches_filter(cond_filter,u, loc, board, use_flat_tod);
|
||||
}
|
||||
// Handle [or]
|
||||
else if(cond_name == "or") {
|
||||
matches = matches || matches_filter(cond_filter,u, loc, board,use_flat_tod);
|
||||
}
|
||||
// Handle [not]
|
||||
else if(cond_name == "not") {
|
||||
matches = matches && !matches_filter(cond_filter,u, loc, board,use_flat_tod);
|
||||
}
|
||||
|
||||
++cond;
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
} //end namespace unit_filter
|
||||
|
||||
namespace { //begin anonymous namespace
|
||||
|
||||
bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, const display_context * board, bool use_flat_tod)
|
||||
{
|
||||
config::attribute_value cfg_name = cfg["name"];
|
||||
if (!cfg_name.blank() && cfg_name.str() != u.name()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const config::attribute_value cfg_id = cfg["id"];
|
||||
if (!cfg_id.blank()) {
|
||||
const std::string& id = cfg_id;
|
||||
const std::string& this_id = u.id();
|
||||
|
||||
if (id == this_id) {
|
||||
}
|
||||
else if ( id.find(',') == std::string::npos ){
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
const std::vector<std::string>& ids = utils::split(id);
|
||||
if (std::find(ids.begin(), ids.end(), this_id) == ids.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Allow 'speaker' as an alternative to id, since people use it so often
|
||||
config::attribute_value cfg_speaker = cfg["speaker"];
|
||||
if (!cfg_speaker.blank() && cfg_speaker.str() != u.id()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(cfg.has_child("filter_location")) {
|
||||
assert(board != NULL);
|
||||
const vconfig& t_cfg = cfg.child("filter_location");
|
||||
terrain_filter t_filter(t_cfg, board->units(), use_flat_tod);
|
||||
if(!t_filter.match(loc)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const vconfig& filter_side = cfg.child("filter_side");
|
||||
if(!filter_side.null()) {
|
||||
side_filter s_filter(filter_side);
|
||||
if(!s_filter.match(u.side()))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Also allow filtering on location ranges outside of the location filter
|
||||
config::attribute_value cfg_x = cfg["x"];
|
||||
config::attribute_value cfg_y = cfg["y"];
|
||||
if (!cfg_x.blank() || !cfg_y.blank()){
|
||||
if(cfg_x == "recall" && cfg_y == "recall") {
|
||||
//locations on the map are considered to not be on a recall list
|
||||
if ((!board && loc.valid()) ||
|
||||
(board && board->map().on_board(loc)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} else if(cfg_x.empty() && cfg_y.empty()) {
|
||||
return false;
|
||||
} else if(!loc.matches_range(cfg_x, cfg_y)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The type could be a comma separated list of types
|
||||
config::attribute_value cfg_type = cfg["type"];
|
||||
if (!cfg_type.blank())
|
||||
{
|
||||
const std::string type_ids = cfg_type.str();
|
||||
const std::string& this_type = u.type_id();
|
||||
|
||||
// We only do the full CSV search if we find a comma in there,
|
||||
// and if the subsequence is found within the main sequence.
|
||||
// This is because doing the full CSV split is expensive.
|
||||
if ( type_ids == this_type ) {
|
||||
// pass
|
||||
} else if ( type_ids.find(',') != std::string::npos &&
|
||||
type_ids.find(this_type) != std::string::npos ) {
|
||||
const std::vector<std::string>& vals = utils::split(type_ids);
|
||||
|
||||
if(std::find(vals.begin(),vals.end(),this_type) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The variation_type could be a comma separated list of types
|
||||
config::attribute_value cfg_variation_type = cfg["variation"];
|
||||
if (!cfg_variation_type.blank())
|
||||
{
|
||||
const std::string type_ids = cfg_variation_type.str();
|
||||
const std::string& this_type = u.variation();
|
||||
|
||||
// We only do the full CSV search if we find a comma in there,
|
||||
// and if the subsequence is found within the main sequence.
|
||||
// This is because doing the full CSV split is expensive.
|
||||
if ( type_ids == this_type ) {
|
||||
// pass
|
||||
} else if ( type_ids.find(',') != std::string::npos &&
|
||||
type_ids.find(this_type) != std::string::npos ) {
|
||||
const std::vector<std::string>& vals = utils::split(type_ids);
|
||||
|
||||
if(std::find(vals.begin(),vals.end(),this_type) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The has_variation_type could be a comma separated list of types
|
||||
config::attribute_value cfg_has_variation_type = cfg["has_variation"];
|
||||
if (!cfg_has_variation_type.blank())
|
||||
{
|
||||
const std::string& var_ids = cfg_has_variation_type.str();
|
||||
const std::string& this_var = u.variation();
|
||||
|
||||
if ( var_ids == this_var ) {
|
||||
// pass
|
||||
} else {
|
||||
|
||||
bool match = false;
|
||||
const std::vector<std::string>& variation_types = utils::split(var_ids);
|
||||
// If this unit is a variation itself then search in the base unit's variations.
|
||||
const unit_type* const type = this_var.empty() ? &u.type() : unit_types.find(u.type().base_id());
|
||||
assert(type);
|
||||
|
||||
BOOST_FOREACH(const std::string& variation_id, variation_types) {
|
||||
if (type->has_variation(variation_id)) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_ability = cfg["ability"];
|
||||
if (!cfg_ability.blank())
|
||||
{
|
||||
std::string ability = cfg_ability;
|
||||
if(u.has_ability_by_id(ability)) {
|
||||
// pass
|
||||
} else if ( ability.find(',') != std::string::npos ) {
|
||||
const std::vector<std::string>& vals = utils::split(ability);
|
||||
bool has_ability = false;
|
||||
for(std::vector<std::string>::const_iterator this_ability = vals.begin(); this_ability != vals.end(); ++this_ability) {
|
||||
if(u.has_ability_by_id(*this_ability)) {
|
||||
has_ability = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!has_ability) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_race = cfg["race"];
|
||||
if (!cfg_race.blank()) {
|
||||
std::string race = cfg_race;
|
||||
|
||||
if(race != u.race()->id()) {
|
||||
const std::vector<std::string>& vals = utils::split(race);
|
||||
if(std::find(vals.begin(), vals.end(), u.race()->id()) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_gender = cfg["gender"];
|
||||
if (!cfg_gender.blank() && string_gender(cfg_gender) != u.gender()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_side = cfg["side"];
|
||||
if (!cfg_side.blank() && cfg_side.to_int() != u.side()) {
|
||||
std::string side = cfg_side;
|
||||
if ( side.find(',') == std::string::npos ) {
|
||||
return false;
|
||||
}
|
||||
std::vector<std::string> vals = utils::split(side);
|
||||
if (std::find(vals.begin(), vals.end(), str_cast(u.side())) == vals.end()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_has_weapon = cfg["has_weapon"];
|
||||
if (!cfg_has_weapon.blank()) {
|
||||
std::string weapon = cfg_has_weapon;
|
||||
bool has_weapon = false;
|
||||
const std::vector<attack_type>& attacks = u.attacks();
|
||||
for(std::vector<attack_type>::const_iterator i = attacks.begin();
|
||||
i != attacks.end(); ++i) {
|
||||
if(i->id() == weapon) {
|
||||
has_weapon = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!has_weapon) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_role = cfg["role"];
|
||||
if (!cfg_role.blank() && cfg_role.str() != u.get_role()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_ai_special = cfg["ai_special"];
|
||||
if (!cfg_ai_special.blank() && ((cfg_ai_special.str() == "guardian") != u.get_state(unit::STATE_GUARDIAN))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_canrecruit = cfg["canrecruit"];
|
||||
if (!cfg_canrecruit.blank() && cfg_canrecruit.to_bool() != u.can_recruit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_recall_cost = cfg["recall_cost"];
|
||||
if (!cfg_recall_cost.blank() && cfg_recall_cost.to_int(-1) != u.recall_cost()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_level = cfg["level"];
|
||||
if (!cfg_level.blank() && cfg_level.to_int(-1) != u.level()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_defense = cfg["defense"];
|
||||
if (!cfg_defense.blank() && cfg_defense.to_int(-1) != u.defense_modifier(board->map().get_terrain(loc))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
config::attribute_value cfg_movement = cfg["movement_cost"];
|
||||
if (!cfg_movement.blank() && cfg_movement.to_int(-1) != u.movement_cost(board->map().get_terrain(loc))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now start with the new WML based comparison.
|
||||
// If a key is in the unit and in the filter, they should match
|
||||
// filter only => not for us
|
||||
// unit only => not filtered
|
||||
const vconfig::child_list& wmlcfgs = cfg.get_children("filter_wml");
|
||||
if (!wmlcfgs.empty()) {
|
||||
config unit_cfg;
|
||||
for (unsigned i = 0; i < wmlcfgs.size(); ++i)
|
||||
{
|
||||
config fwml = wmlcfgs[i].get_parsed_config();
|
||||
/* Check if the filter only cares about variables.
|
||||
If so, no need to serialize the whole unit. */
|
||||
config::const_attr_itors ai = fwml.attribute_range();
|
||||
config::all_children_itors ci = fwml.all_children_range();
|
||||
if (std::distance(ai.first, ai.second) == 0 &&
|
||||
std::distance(ci.first, ci.second) == 1 &&
|
||||
ci.first->key == "variables") {
|
||||
if (!u.variables().matches(ci.first->cfg))
|
||||
return false;
|
||||
} else {
|
||||
if (unit_cfg.empty())
|
||||
u.write(unit_cfg);
|
||||
if (!unit_cfg.matches(fwml))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.has_child("filter_vision")) {
|
||||
const vconfig::child_list& vis_filt = cfg.get_children("filter_vision");
|
||||
vconfig::child_list::const_iterator i, i_end = vis_filt.end();
|
||||
for (i = vis_filt.begin(); i != i_end; ++i) {
|
||||
bool visible = (*i)["visible"].to_bool(true);
|
||||
std::set<int> viewers;
|
||||
// Use standard side filter
|
||||
side_filter ssf(*i);
|
||||
std::vector<int> sides = ssf.get_teams();
|
||||
viewers.insert(sides.begin(), sides.end());
|
||||
if (viewers.empty()) {
|
||||
return false;
|
||||
}
|
||||
std::set<int>::const_iterator viewer, viewer_end = viewers.end();
|
||||
for (viewer = viewers.begin(); viewer != viewer_end; ++viewer) {
|
||||
bool fogged = board->teams()[*viewer - 1].fogged(loc);
|
||||
bool hiding = u.invisible(loc/*, false(?) */);
|
||||
bool unit_hidden = fogged || hiding;
|
||||
if (visible == unit_hidden) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.has_child("filter_adjacent")) {
|
||||
assert(board);
|
||||
const unit_map& units = board->units();
|
||||
map_location adjacent[6];
|
||||
get_adjacent_tiles(loc, adjacent);
|
||||
vconfig::child_list::const_iterator i, i_end;
|
||||
const vconfig::child_list& adj_filt = cfg.get_children("filter_adjacent");
|
||||
for (i = adj_filt.begin(), i_end = adj_filt.end(); i != i_end; ++i) {
|
||||
int match_count=0;
|
||||
config::attribute_value i_adjacent = (*i)["adjacent"];
|
||||
std::vector<map_location::DIRECTION> dirs = !i_adjacent.blank() ?
|
||||
map_location::parse_directions(i_adjacent) : map_location::default_dirs();
|
||||
std::vector<map_location::DIRECTION>::const_iterator j, j_end = dirs.end();
|
||||
for (j = dirs.begin(); j != j_end; ++j) {
|
||||
unit_map::const_iterator unit_itor = units.find(adjacent[*j]);
|
||||
if (unit_itor == units.end()
|
||||
|| !unit_filter::matches_filter(*i, *unit_itor, unit_itor->get_location(), board, use_flat_tod)) {
|
||||
continue;
|
||||
}
|
||||
config::attribute_value i_is_enemy = (*i)["is_enemy"];
|
||||
if (i_is_enemy.blank() || i_is_enemy.to_bool() ==
|
||||
board->teams()[u.side() - 1].is_enemy(unit_itor->side())) {
|
||||
++match_count;
|
||||
}
|
||||
}
|
||||
static std::vector<std::pair<int,int> > default_counts = utils::parse_ranges("1-6");
|
||||
config::attribute_value i_count = (*i)["count"];
|
||||
std::vector<std::pair<int,int> > counts = !i_count.blank()
|
||||
? utils::parse_ranges(i_count) : default_counts;
|
||||
if(!in_ranges(match_count, counts)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_find_in = cfg["find_in"];
|
||||
if (!cfg_find_in.blank()) {
|
||||
// Allow filtering by searching a stored variable of units
|
||||
variable_info vi(cfg_find_in, false, variable_info::TYPE_CONTAINER);
|
||||
if(!vi.is_valid) return false;
|
||||
if(vi.explicit_index) {
|
||||
config::const_child_iterator i = vi.vars->child_range(vi.key).first;
|
||||
std::advance(i, vi.index);
|
||||
if ((*i)["id"] != u.id()) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!vi.vars->find_child(vi.key, "id", u.id()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
config::attribute_value cfg_formula = cfg["formula"];
|
||||
if (!cfg_formula.blank()) {
|
||||
if (!u.formula_manager().matches_filter(cfg_formula, loc, u)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value cfg_lua_function = cfg["lua_function"];
|
||||
if (!cfg_lua_function.blank()) {
|
||||
bool b = resources::lua_kernel->run_filter(cfg_lua_function.str().c_str(), u);
|
||||
if (!b) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} //end anonymous namespace
|
39
src/unit_filter.hpp
Normal file
39
src/unit_filter.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright (C) 2014 by Chris Beck <render787@gmail.com>
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This namespace contains the function that checks if a unit matches
|
||||
* a filter. It helps by simplifying the unit object (which before now
|
||||
* holds the "match" function).
|
||||
*
|
||||
* TODO:
|
||||
* Make a class that abstracts a unit filter, assembles the constituent
|
||||
* side filters and terrain filters and conditional filters, and caches
|
||||
* these to speed up repeated application of the filter.
|
||||
*/
|
||||
|
||||
class display_context;
|
||||
class unit;
|
||||
class vconfig;
|
||||
struct map_location;
|
||||
|
||||
namespace unit_filter {
|
||||
|
||||
bool matches_filter(const vconfig& cfg,const unit & u, const map_location& loc, const display_context * board, bool use_flat_tod=false);
|
||||
/// Determine if *this matches @a filter at its current location.
|
||||
/// (Only use for units currently on the map; otherwise use the overload
|
||||
/// that takes a location, possibly with a null location.)
|
||||
bool matches_filter(const vconfig& filter, const unit & u, const display_context* board, bool use_flat_tod=false);
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue