From 4046666bee764463ecfd0464c43f534361deab68 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Wed, 2 Jul 2014 21:29:04 -0400 Subject: [PATCH 1/7] fixup lines with two closers on a line in wml test directory wmlindent chokes on these commit made with the following command: find data/test/scenarios/ -type f -print0 | xargs -0 sed -i "s|^\([[:space:]]*\[\/.*\]\)[[:space:]]*)\}[[:space:]]*$|\1\n)}|" --- data/test/scenarios/break_replay_with_lua_random.cfg | 6 ++++-- data/test/scenarios/event_handlers_in_events.cfg | 3 ++- data/test/scenarios/move_skip_sighted.cfg | 3 ++- data/test/scenarios/test_unit_map.cfg | 6 ++++-- data/test/scenarios/units_offmap_goto_recall.cfg | 6 ++++-- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/data/test/scenarios/break_replay_with_lua_random.cfg b/data/test/scenarios/break_replay_with_lua_random.cfg index c45b6cd9da5a..2ed0bd012749 100644 --- a/data/test/scenarios/break_replay_with_lua_random.cfg +++ b/data/test/scenarios/break_replay_with_lua_random.cfg @@ -71,7 +71,8 @@ code =<< wesnoth.set_variable("rnd_num", math.random(200)) >> - [/lua])} + [/lua] +)} {TEST_BREAK_REPLAY "fixed_lua_random_replay_with_sync_choice" ([lua] @@ -82,4 +83,5 @@ end) wesnoth.set_variable("rnd_num", result.value) >> - [/lua])} + [/lua] +)} diff --git a/data/test/scenarios/event_handlers_in_events.cfg b/data/test/scenarios/event_handlers_in_events.cfg index ea781140529e..61309e111d2e 100644 --- a/data/test/scenarios/event_handlers_in_events.cfg +++ b/data/test/scenarios/event_handlers_in_events.cfg @@ -189,7 +189,8 @@ name=post_advance {VARIABLE pass_test 1} [/my_event] - [/variables])} + [/variables] +)} [store_unit] [filter] x=1 diff --git a/data/test/scenarios/move_skip_sighted.cfg b/data/test/scenarios/move_skip_sighted.cfg index 2e5948d426b1..3dc809d5a0e7 100644 --- a/data/test/scenarios/move_skip_sighted.cfg +++ b/data/test/scenarios/move_skip_sighted.cfg @@ -61,7 +61,8 @@ id=bob x={STOP_X} y={STOP_Y} - [/have_unit])} + [/have_unit] +)} [/event] [/test] #enddef diff --git a/data/test/scenarios/test_unit_map.cfg b/data/test/scenarios/test_unit_map.cfg index 1dcf50f30495..f96737aab9e1 100644 --- a/data/test/scenarios/test_unit_map.cfg +++ b/data/test/scenarios/test_unit_map.cfg @@ -9,14 +9,16 @@ [have_unit] x,y=9,5 [/have_unit] - [/not])} + [/not] +)} #enddef #define ASSERT_YES_9_5 {ASSERT ( [have_unit] x,y=9,5 - [/have_unit])} + [/have_unit] +)} #enddef diff --git a/data/test/scenarios/units_offmap_goto_recall.cfg b/data/test/scenarios/units_offmap_goto_recall.cfg index 427bef270ad7..06a20fc94da9 100644 --- a/data/test/scenarios/units_offmap_goto_recall.cfg +++ b/data/test/scenarios/units_offmap_goto_recall.cfg @@ -20,13 +20,15 @@ side = 1 search_recall_list = no [/have_unit] - [/not])} + [/not] +)} {RETURN ( [have_unit] id = Charlie canrecruit = no side = 1 search_recall_list = yes - [/have_unit])} + [/have_unit] +)} [/event] )} From d803cde06a9d673be055eb3728f97374544ab0b9 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 3 Jul 2014 03:47:24 -0400 Subject: [PATCH 2/7] 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. --- projectfiles/CodeBlocks/wesnoth.cbp | 2 + projectfiles/VC9/wesnoth.vcproj | 8 + src/CMakeLists.txt | 1 + src/SConscript | 1 + src/actions/create.cpp | 15 +- src/ai/composite/goal.cpp | 6 +- src/ai/recruitment/recruitment.cpp | 5 +- src/ai/testing/aspect_attacks.cpp | 5 +- src/game_events/action_wml.cpp | 29 +- src/game_events/conditional_wml.cpp | 6 +- src/game_events/entity_location.cpp | 5 +- src/pathfind/teleport.cpp | 4 +- src/scripting/lua.cpp | 11 +- src/side_filter.cpp | 6 +- src/terrain_filter.cpp | 3 +- src/unit.cpp | 408 +------------------------ src/unit.hpp | 13 +- src/unit_abilities.cpp | 14 +- src/unit_animation.cpp | 7 +- src/unit_display.cpp | 3 +- src/unit_filter.cpp | 447 ++++++++++++++++++++++++++++ src/unit_filter.hpp | 39 +++ 22 files changed, 578 insertions(+), 460 deletions(-) create mode 100644 src/unit_filter.cpp create mode 100644 src/unit_filter.hpp diff --git a/projectfiles/CodeBlocks/wesnoth.cbp b/projectfiles/CodeBlocks/wesnoth.cbp index d56e2a7110e8..94c78c2122ae 100644 --- a/projectfiles/CodeBlocks/wesnoth.cbp +++ b/projectfiles/CodeBlocks/wesnoth.cbp @@ -1039,6 +1039,8 @@ + + diff --git a/projectfiles/VC9/wesnoth.vcproj b/projectfiles/VC9/wesnoth.vcproj index b4ec3dffd910..9a7942c15c08 100644 --- a/projectfiles/VC9/wesnoth.vcproj +++ b/projectfiles/VC9/wesnoth.vcproj @@ -21192,6 +21192,14 @@ RelativePath="..\..\src\unit_drawer.hpp" > + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d4da828be3e8..d4f7ac899f3a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/SConscript b/src/SConscript index 1ff0c318d2c1..7fa19d90ceec 100644 --- a/src/SConscript +++ b/src/SConscript @@ -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 diff --git a/src/actions/create.cpp b/src/actions/create.cpp index 6333546f23c3..c2849e73cafa 100644 --- a/src/actions/create.cpp +++ b/src/actions/create.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. diff --git a/src/ai/composite/goal.cpp b/src/ai/composite/goal.cpp index 3c0eb8d10c13..9ddef1c35ab2 100644 --- a/src/ai/composite/goal.cpp +++ b/src/ai/composite/goal.cpp @@ -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 @@ -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()); } diff --git a/src/ai/recruitment/recruitment.cpp b/src/ai/recruitment/recruitment.cpp index 03f3a983bf9f..446c27c43445 100644 --- a/src/ai/recruitment/recruitment.cpp +++ b/src/ai/recruitment/recruitment.cpp @@ -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; } diff --git a/src/ai/testing/aspect_attacks.cpp b/src/ai/testing/aspect_attacks.cpp index 404c84bcab24..56a5d1c78744 100644 --- a/src/ai/testing/aspect_attacks.cpp +++ b/src/ai/testing/aspect_attacks.cpp @@ -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 aspect_attacks::analyze_targets() const std::vector 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 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]; diff --git a/src/game_events/action_wml.cpp b/src/game_events/action_wml.cpp index dcf60329afb2..7bcbbe1bab20 100644 --- a/src/game_events/action_wml.cpp +++ b/src/game_events/action_wml.cpp @@ -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 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 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::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::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; } } diff --git a/src/game_events/conditional_wml.cpp b/src/game_events/conditional_wml.cpp index a16b8af512e0..4a2ffdbe555a 100644 --- a/src/game_events/conditional_wml.cpp +++ b/src/game_events/conditional_wml.cpp @@ -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; } } diff --git a/src/game_events/entity_location.cpp b/src/game_events/entity_location.cpp index 806f2396d094..cc0e798981db 100644 --- a/src/game_events/entity_location.cpp +++ b/src/game_events/entity_location.cpp @@ -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); } diff --git a/src/pathfind/teleport.cpp b/src/pathfind/teleport.cpp index fd4dab886c55..5008232f1c7e 100644 --- a/src/pathfind/teleport.cpp +++ b/src/pathfind/teleport.cpp @@ -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 @@ -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); diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 234dfdf37057..1992a608fd9f 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -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)); } diff --git a/src/side_filter.cpp b/src/side_filter.cpp index 1492df39f267..050e303afac8 100644 --- a/src/side_filter.cpp +++ b/src/side_filter.cpp @@ -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 @@ -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; } diff --git a/src/terrain_filter.cpp b/src/terrain_filter.cpp index 663498e3890d..8c38921ef0df 100644 --- a/src/terrain_filter.cpp +++ b/src/terrain_filter.cpp @@ -26,6 +26,7 @@ #include "terrain_filter.hpp" #include "tod_manager.hpp" #include "unit.hpp" +#include "unit_filter.hpp" #include "variable.hpp" #include @@ -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; } diff --git a/src/unit.cpp b/src/unit.cpp index 87b78b592251..931d95fb5056 100644 --- a/src/unit.cpp +++ b/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& 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& 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& 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& 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& vals = utils::split(ability); - bool has_ability = false; - for(std::vector::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& 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 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& attacks = this->attacks(); - for(std::vector::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 viewers; - // Use standard side filter - side_filter ssf(*i); - std::vector sides = ssf.get_teams(); - viewers.insert(sides.begin(), sides.end()); - if (viewers.empty()) { - return false; - } - std::set::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 dirs = !i_adjacent.blank() ? - map_location::parse_directions(i_adjacent) : map_location::default_dirs(); - std::vector::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 > default_counts = utils::parse_ranges("1-6"); - config::attribute_value i_count = (*i)["count"]; - std::vector > 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"]; diff --git a/src/unit.hpp b/src/unit.hpp index 08447ee4311d..d2f3a3701c81 100644 --- a/src/unit.hpp +++ b/src/unit.hpp @@ -137,6 +137,7 @@ class unit /** 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 @@ class unit 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& overlays() const { return overlays_; } void write(config& cfg) const; @@ -382,9 +377,6 @@ class unit 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 @@ class unit 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*/ diff --git a/src/unit_abilities.cpp b/src/unit_abilities.cpp index 0eb01d544ef7..8343f7c67637 100644 --- a/src/unit_abilities.cpp +++ b/src/unit_abilities.cpp @@ -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 @@ -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 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; } } diff --git a/src/unit_animation.cpp b/src/unit_animation.cpp index 37feef62b5ad..f8c9fa52c719 100644 --- a/src/unit_animation.cpp +++ b/src/unit_animation.cpp @@ -23,6 +23,7 @@ #include "resources.hpp" #include "unit.hpp" #include "unit_animation_component.hpp" +#include "unit_filter.hpp" #include "variable.hpp" #include @@ -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::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::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++; } diff --git a/src/unit_display.cpp b/src/unit_display.cpp index 39923aa6e4c7..4540d0bc9586 100644 --- a/src/unit_display.cpp +++ b/src/unit_display.cpp @@ -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 @@ -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; } } diff --git a/src/unit_filter.cpp b/src/unit_filter.cpp new file mode 100644 index 000000000000..69815554a10e --- /dev/null +++ b/src/unit_filter.cpp @@ -0,0 +1,447 @@ +/* + Copyright (C) 2014 by Chris Beck + 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 + +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& 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& 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& 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& 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& vals = utils::split(ability); + bool has_ability = false; + for(std::vector::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& 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 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& attacks = u.attacks(); + for(std::vector::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 viewers; + // Use standard side filter + side_filter ssf(*i); + std::vector sides = ssf.get_teams(); + viewers.insert(sides.begin(), sides.end()); + if (viewers.empty()) { + return false; + } + std::set::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 dirs = !i_adjacent.blank() ? + map_location::parse_directions(i_adjacent) : map_location::default_dirs(); + std::vector::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 > default_counts = utils::parse_ranges("1-6"); + config::attribute_value i_count = (*i)["count"]; + std::vector > 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 diff --git a/src/unit_filter.hpp b/src/unit_filter.hpp new file mode 100644 index 000000000000..da337a5ce473 --- /dev/null +++ b/src/unit_filter.hpp @@ -0,0 +1,39 @@ +/* + Copyright (C) 2014 by Chris Beck + 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); + +} From d86b59f08a8b84fe5d42e2d717084a6b06bca735 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 3 Jul 2014 05:30:47 -0400 Subject: [PATCH 3/7] add filter_context class, use in unit_filter The filter context is, game_board + tod manager. game_display can (and now does) implement this interface, also game_state. This permits both animations and engine components to use it. --- src/actions/create.cpp | 5 +-- src/ai/composite/goal.cpp | 4 +-- src/ai/recruitment/recruitment.cpp | 5 +-- src/ai/testing/aspect_attacks.cpp | 4 +-- src/display.cpp | 10 ++++++ src/display.hpp | 4 ++- src/filter_context.hpp | 43 ++++++++++++++++++++++++++ src/game_board.hpp | 2 +- src/game_display.hpp | 2 ++ src/game_events/action_wml.cpp | 28 ++++++++--------- src/game_events/conditional_wml.cpp | 4 +-- src/game_events/entity_location.cpp | 2 +- src/game_state.hpp | 8 ++++- src/pathfind/teleport.cpp | 2 +- src/play_controller.cpp | 3 +- src/play_controller.hpp | 2 +- src/resources.cpp | 1 + src/resources.hpp | 2 ++ src/scripting/lua.cpp | 10 +++--- src/side_filter.cpp | 4 +-- src/terrain_filter.cpp | 2 +- src/unit.cpp | 2 +- src/unit_abilities.cpp | 12 ++++---- src/unit_animation.cpp | 4 +-- src/unit_display.cpp | 2 +- src/unit_filter.cpp | 47 +++++++++++++++-------------- src/unit_filter.hpp | 6 ++-- 27 files changed, 145 insertions(+), 75 deletions(-) create mode 100644 src/filter_context.hpp diff --git a/src/actions/create.cpp b/src/actions/create.cpp index c2849e73cafa..530865bce6ef 100644 --- a/src/actions/create.cpp +++ b/src/actions/create.cpp @@ -25,6 +25,7 @@ #include "../config.hpp" #include "../config_assign.hpp" +#include "../filter_context.hpp" #include "../game_board.hpp" #include "../game_display.hpp" #include "../game_events/pump.hpp" @@ -434,7 +435,7 @@ namespace { // Helpers for get_recalls() if ( unit_filter::matches_filter( rfilter, recall_unit, map_location::null_location(), - resources::gameboard) ) + resources::filter_con) ) { result.push_back(recall_unit_ptr); if ( already_added != NULL ) @@ -537,7 +538,7 @@ namespace { // Helpers for check_recall_location() if ( !unit_filter::matches_filter(rfilter, recall_unit, map_location::null_location(), - resources::gameboard) ) + resources::filter_con) ) return RECRUIT_NO_ABLE_LEADER; // Make sure the unit is on a keep. diff --git a/src/ai/composite/goal.cpp b/src/ai/composite/goal.cpp index 9ddef1c35ab2..c8f24263afb9 100644 --- a/src/ai/composite/goal.cpp +++ b/src/ai/composite/goal.cpp @@ -135,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 (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::gameboard)) { + if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::filter_con)) { LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value() << "\n"; *target_list = target(u.get_location(), value(), target::EXPLICIT); } @@ -264,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 (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::gameboard)) { + if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::filter_con)) { DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected\n"; items.insert(u.get_location()); } diff --git a/src/ai/recruitment/recruitment.cpp b/src/ai/recruitment/recruitment.cpp index 446c27c43445..0df705509762 100644 --- a/src/ai/recruitment/recruitment.cpp +++ b/src/ai/recruitment/recruitment.cpp @@ -25,6 +25,7 @@ #include "../manager.hpp" #include "../../actions/attack.hpp" #include "../../attack_prediction.hpp" +#include "../../filter_context.hpp" #include "../../game_board.hpp" #include "../../game_display.hpp" #include "../../log.hpp" @@ -252,7 +253,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 (!unit_filter::matches_filter(filter, *recall, map_location::null_location(), resources::gameboard)) { + if (!unit_filter::matches_filter(filter, *recall, map_location::null_location(), resources::filter_con)) { continue; } data.recruits.insert(recall->type_id()); @@ -477,7 +478,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 (!unit_filter::matches_filter(filter, *recall_unit, map_location::null_location(), resources::gameboard)) { + if (!unit_filter::matches_filter(filter, *recall_unit, map_location::null_location(), resources::filter_con)) { LOG_AI_RECRUITMENT << "Refused recall because of filter: " << recall_unit->id() << "\n"; continue; } diff --git a/src/ai/testing/aspect_attacks.cpp b/src/ai/testing/aspect_attacks.cpp index 56a5d1c78744..0571864211dd 100644 --- a/src/ai/testing/aspect_attacks.cpp +++ b/src/ai/testing/aspect_attacks.cpp @@ -76,7 +76,7 @@ boost::shared_ptr aspect_attacks::analyze_targets() const std::vector 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 (!unit_filter::matches_filter(vconfig(filter_own_), *i, i->get_location(), resources::gameboard)) { + if (!unit_filter::matches_filter(vconfig(filter_own_), *i, i->get_location(), resources::filter_con)) { continue; } unit_locs.push_back(i->get_location()); @@ -99,7 +99,7 @@ boost::shared_ptr aspect_attacks::analyze_targets() const if (current_team().is_enemy(j->side()) && !j->incapacitated() && !j->invisible(j->get_location())) { - if (!unit_filter::matches_filter(vconfig(filter_enemy_), *j, j->get_location(), resources::gameboard)) { + if (!unit_filter::matches_filter(vconfig(filter_enemy_), *j, j->get_location(), resources::filter_con)) { continue; } map_location adjacent[6]; diff --git a/src/display.cpp b/src/display.cpp index 44d5cba5a7bf..3183dc878b70 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -416,6 +416,16 @@ const time_of_day & display::get_time_of_day(const map_location& /*loc*/) const return tod; } +/** + * Display objects don't hold a tod maanger, instead game_display objects do. If the base version of this method is called, + * try to get it from resources and use an assert to check for failure. + */ +const tod_manager & display::get_tod_man() const +{ + assert(resources::tod_manager); + return *resources::tod_manager; +} + void display::update_tod() { const time_of_day& tod = get_time_of_day(); tod_color col = color_adjust_ + tod.color; diff --git a/src/display.hpp b/src/display.hpp index eb153563fdc1..484a7d63366b 100644 --- a/src/display.hpp +++ b/src/display.hpp @@ -49,6 +49,7 @@ namespace wb { #include "animated.hpp" #include "display_context.hpp" +#include "filter_context.hpp" #include "font.hpp" #include "image.hpp" //only needed for enums (!) #include "key.hpp" @@ -71,7 +72,7 @@ namespace wb { class gamemap; -class display +class display : public filter_context { public: display(const display_context * dc, CVideo& video, boost::weak_ptr wb, @@ -164,6 +165,7 @@ class display void change_display_context(const display_context * dc); const display_context & get_disp_context() const { return *dc_; } + virtual const tod_manager & get_tod_man() const; //!< This is implemented properly in game_display. The display:: impl could be pure virtual here but we decide not to. void reset_halo_manager(); void reset_halo_manager(halo::manager & hm); diff --git a/src/filter_context.hpp b/src/filter_context.hpp new file mode 100644 index 000000000000..7af71c68fce6 --- /dev/null +++ b/src/filter_context.hpp @@ -0,0 +1,43 @@ +/* + Copyright (C) 2014 by Chris Beck + 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 class is an abstract base class which represents a display context + * (game map, units, and teams) together with a TOD manager. This, plus + * a lua kernel (currently a singleton) is sufficient to evaluate filters. + * + **/ + +#ifndef FILTER_CONTEXT_HPP_INCLUDED +#define FILTER_CONTEXT_HPP_INCLUDED + +#include + +class display_context; +class tod_manager; + +class filter_context { +public: + // accessors + + virtual const display_context & get_disp_context() const = 0; + virtual const tod_manager & get_tod_man() const = 0; + + // Dtor + + virtual ~filter_context() {} +}; + +#endif diff --git a/src/game_board.hpp b/src/game_board.hpp index 42d9adfc75ed..cad1a9958cff 100644 --- a/src/game_board.hpp +++ b/src/game_board.hpp @@ -60,7 +60,7 @@ class game_board : public display_context { friend class play_controller; friend class events::mouse_handler; friend class events::menu_handler; - friend struct game_state; + friend class game_state; /** * Temporary unit move structs: diff --git a/src/game_display.hpp b/src/game_display.hpp index 76c678f91d60..59b5314b6683 100644 --- a/src/game_display.hpp +++ b/src/game_display.hpp @@ -130,6 +130,8 @@ class game_display : public display bool has_time_area() const; + const tod_manager & get_tod_man() const { return tod_manager_; } //find(event_info.loc2); } else if(speaker_str != "narrator") { for(speaker = units->begin(); speaker != units->end(); ++speaker){ - if ( unit_filter::matches_filter(cfg,*speaker, resources::gameboard) ) + if ( unit_filter::matches_filter(cfg,*speaker, resources::filter_con) ) break; } } @@ -779,7 +779,7 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg) std::vector healers; if (!healers_filter.null()) { BOOST_FOREACH(unit& u, *units) { - if ( unit_filter::matches_filter(healers_filter,u, resources::gameboard) && u.has_ability_type("heals") ) { + if ( unit_filter::matches_filter(healers_filter,u, resources::filter_con) && u.has_ability_type("heals") ) { healers.push_back(&u); } } @@ -800,7 +800,7 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg) u = units->find(event_info.loc1); if(!u.valid()) return; } - else if ( !unit_filter::matches_filter(healed_filter,*u, resources::gameboard) ) continue; + else if ( !unit_filter::matches_filter(healed_filter,*u, resources::filter_con) ) continue; int heal_amount = u->max_hitpoints() - u->hitpoints(); if(amount.blank() || amount == "full") u->set_hitpoints(u->max_hitpoints()); @@ -859,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_filter::matches_filter(cfg.child("secondary_unit"), *unit, resources::gameboard) ) + if ( unit_filter::matches_filter(cfg.child("secondary_unit"), *unit, resources::filter_con) ) { killer_loc = entity_location(*unit); secondary_unit = true; @@ -874,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 dead_men_walking; BOOST_FOREACH(unit & u, *resources::units){ - if ( unit_filter::matches_filter(cfg,u, resources::gameboard) ) { + if ( unit_filter::matches_filter(cfg,u, resources::filter_con) ) { dead_men_walking.push_back(&u); } } @@ -948,7 +948,7 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg) { for(std::vector::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 (unit_filter::matches_filter(cfg, *(*j), map_location(), resources::gameboard)) { + if (unit_filter::matches_filter(cfg, *(*j), map_location(), resources::filter_con)) { j = pi->recall_list().erase(j); } else { ++j; @@ -1416,7 +1416,7 @@ WML_HANDLER_FUNCTION(object, event_info, cfg) map_location loc; if(!filter.null()) { BOOST_FOREACH(const unit &u, *resources::units) { - if ( unit_filter::matches_filter(filter,u, resources::gameboard) ) { + if ( unit_filter::matches_filter(filter,u, resources::filter_con) ) { loc = u.get_location(); break; } @@ -1431,7 +1431,7 @@ WML_HANDLER_FUNCTION(object, event_info, cfg) std::string command_type = "then"; - if ( u != resources::units->end() && (filter.null() || unit_filter::matches_filter(filter,*u, resources::gameboard)) ) + if ( u != resources::units->end() && (filter.null() || unit_filter::matches_filter(filter,*u, resources::filter_con)) ) { ///@deprecated This can be removed (and a proper duration=level implemented) after 1.11.2 /// Don't forget to remove it from wmllint too! @@ -1546,7 +1546,7 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) for(std::vector::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 (unit_filter::matches_filter(unit_filter, *(*u), map_location(), resources::gameboard)) { + if (unit_filter::matches_filter(unit_filter, *(*u), map_location(), resources::filter_con)) { DBG_NG << (*u)->id() << " matched the filter...\n"; const unit_ptr to_recruit = *u; const unit* pass_check = to_recruit.get(); @@ -1557,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() || unit_filter::matches_filter(leader_filter, *leader, resources::gameboard)) && - unit_filter::matches_filter(vconfig(leader->recall_filter()), *(*u),map_location(), resources::gameboard) ) { + if ( (leader_filter.null() || unit_filter::matches_filter(leader_filter, *leader, resources::filter_con)) && + unit_filter::matches_filter(vconfig(leader->recall_filter()), *(*u),map_location(), resources::filter_con) ) { 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(); @@ -1726,7 +1726,7 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg) } unit_map::iterator itor; BOOST_FOREACH(unit &u, *resources::units) { - if ( unit_filter::matches_filter(filter,u, resources::gameboard) ) { + if ( unit_filter::matches_filter(filter,u, resources::filter_con) ) { u.set_role(cfg["role"]); found = true; break; @@ -1763,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 (unit_filter::matches_filter(filter, *u, map_location(), resources::gameboard)) { + if (unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)) { u->set_role(cfg["role"]); found=true; break; @@ -2287,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 ( unit_filter::matches_filter(filter,*u, resources::gameboard) ) + if ( unit_filter::matches_filter(filter,*u, resources::filter_con) ) break; } } diff --git a/src/game_events/conditional_wml.cpp b/src/game_events/conditional_wml.cpp index 4a2ffdbe555a..ba41a0a09287 100644 --- a/src/game_events/conditional_wml.cpp +++ b/src/game_events/conditional_wml.cpp @@ -76,7 +76,7 @@ namespace { // Support functions int match_count = 0; BOOST_FOREACH(const unit &i, *resources::units) { - if ( i.hitpoints() > 0 && unit_filter::matches_filter(*u,i, resources::gameboard) ) { + if ( i.hitpoints() > 0 && unit_filter::matches_filter(*u,i, resources::filter_con) ) { ++match_count; if(counts == default_counts) { // by default a single match is enough, so avoid extra work @@ -97,7 +97,7 @@ namespace { // Support functions break; } scoped_recall_unit auto_store("this_unit", team->save_id(), t); - if ( unit_filter::matches_filter(*u,*team->recall_list()[t], resources::gameboard) ) { + if ( unit_filter::matches_filter(*u,*team->recall_list()[t], resources::filter_con) ) { ++match_count; } } diff --git a/src/game_events/entity_location.cpp b/src/game_events/entity_location.cpp index cc0e798981db..310b3c3f2bbf 100644 --- a/src/game_events/entity_location.cpp +++ b/src/game_events/entity_location.cpp @@ -101,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 unit_filter::matches_filter(filter, *un_it, filter_loc_, resources::gameboard) && + return unit_filter::matches_filter(filter, *un_it, filter_loc_, resources::filter_con) && matches_unit(un_it); } diff --git a/src/game_state.hpp b/src/game_state.hpp index 25928837256b..9629ee901ad3 100644 --- a/src/game_state.hpp +++ b/src/game_state.hpp @@ -17,6 +17,7 @@ class config; +#include "filter_context.hpp" #include "game_board.hpp" #include "game_data.hpp" #include "tod_manager.hpp" @@ -25,7 +26,9 @@ class config; namespace pathfind { class manager; } -struct game_state { +class game_state : public filter_context +{ +public: const config& level_; game_data gamedata_; game_board board_; @@ -43,6 +46,9 @@ struct game_state { void init(int ticks, const config & replay_start); config to_config() const; + + virtual const display_context & get_disp_context() const { return board_; } + virtual const tod_manager & get_tod_man() const { return tod_manager_; } }; #endif diff --git a/src/pathfind/teleport.cpp b/src/pathfind/teleport.cpp index 5008232f1c7e..d4fdefac3fad 100644 --- a/src/pathfind/teleport.cpp +++ b/src/pathfind/teleport.cpp @@ -76,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 (unit_filter::matches_filter(filter, u, loc, resources::gameboard)) { + if (unit_filter::matches_filter(filter, u, loc, resources::filter_con)) { scoped_xy_unit teleport_unit("teleport_unit", loc.x, loc.y, *resources::units); diff --git a/src/play_controller.cpp b/src/play_controller.cpp index ddfc34575690..7520f92d9236 100644 --- a/src/play_controller.cpp +++ b/src/play_controller.cpp @@ -79,6 +79,7 @@ static lg::log_domain log_engine_enemies("engine/enemies"); static void clear_resources() { resources::controller = NULL; + resources::filter_con = NULL; resources::gameboard = NULL; resources::gamedata = NULL; resources::persist = NULL; @@ -145,7 +146,7 @@ play_controller::play_controller(const config& level, saved_game& state_of_game, resources::tod_manager = &gamestate_.tod_manager_; resources::undo_stack = undo_stack_.get(); resources::units = &gamestate_.board_.units_; - + resources::filter_con = &gamestate_; resources::classification = &saved_game_.classification(); resources::mp_settings = &saved_game_.mp_settings(); diff --git a/src/play_controller.hpp b/src/play_controller.hpp index 4af404bd3510..68e60bc434da 100644 --- a/src/play_controller.hpp +++ b/src/play_controller.hpp @@ -67,7 +67,7 @@ namespace wb { } // namespace wb // Holds gamestate related objects -struct game_state; +class game_state; class play_controller : public controller_base, public events::observer, public savegame::savegame_config { diff --git a/src/resources.cpp b/src/resources.cpp index 7c5b6f3db610..b47fdf8c2e53 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -21,6 +21,7 @@ namespace resources game_config_manager *config_manager = NULL; play_controller *controller = NULL; game_data *gamedata = NULL; + filter_context *filter_con = NULL; LuaKernel *lua_kernel = NULL; persist_manager *persist = NULL; game_display *screen = NULL; diff --git a/src/resources.hpp b/src/resources.hpp index 2e87b1a84933..51e9dcec77c2 100644 --- a/src/resources.hpp +++ b/src/resources.hpp @@ -23,6 +23,7 @@ class game_config_manager; class game_display; class gamemap; class game_data; +class filter_context; class LuaKernel; class play_controller; class team; @@ -52,6 +53,7 @@ namespace resources extern persist_manager *persist; extern game_classification *classification; extern game_display *screen; + extern filter_context *filter_con; extern const mp_game_settings *mp_settings; extern soundsource::manager *soundsources; extern std::vector *teams; diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 1992a608fd9f..75319c31f7ad 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -858,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() && !unit_filter::matches_filter(filter, *ui, ui->get_location(), resources::gameboard)) + if (!filter.null() && !unit_filter::matches_filter(filter, *ui, ui->get_location(), resources::filter_con)) continue; new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id()); lua_pushvalue(L, 1); @@ -895,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, unit_filter::matches_filter(filter, *u, map_location(), resources::gameboard)); + lua_pushboolean(L, unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)); return 1; } - lua_pushboolean(L, unit_filter::matches_filter(filter, *u, u->get_location(), resources::gameboard)); + lua_pushboolean(L, unit_filter::matches_filter(filter, *u, u->get_location(), resources::filter_con)); return 1; } @@ -928,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 (!unit_filter::matches_filter(filter, *u, map_location(), resources::gameboard)) + if (!unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)) continue; } new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(s, u->underlying_id()); @@ -2003,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 && unit_filter::matches_filter(filter, *ui,ui->get_location(), resources::gameboard)) + if (on_map && unit_filter::matches_filter(filter, *ui,ui->get_location(), resources::filter_con)) { real_units. push_back(&(*ui)); } diff --git a/src/side_filter.cpp b/src/side_filter.cpp index 050e303afac8..e2b27b790049 100644 --- a/src/side_filter.cpp +++ b/src/side_filter.cpp @@ -136,7 +136,7 @@ bool side_filter::match_internal(const team &t) const if (u.side() != t.side()) { continue; } - if (unit_filter::matches_filter(unit_filter, u, u.get_location(), resources::gameboard, flat_)) { + if (unit_filter::matches_filter(unit_filter, u, u.get_location(), resources::filter_con, flat_)) { found = true; break; } @@ -144,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(unit_filter::matches_filter(unit_filter, *u, u->get_location(), resources::gameboard, flat_)) { + if(unit_filter::matches_filter(unit_filter, *u, u->get_location(), resources::filter_con, flat_)) { found = true; break; } diff --git a/src/terrain_filter.cpp b/src/terrain_filter.cpp index 8c38921ef0df..3310ac32e426 100644 --- a/src/terrain_filter.cpp +++ b/src/terrain_filter.cpp @@ -154,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() || !unit_filter::matches_filter(unit_filter, *u, loc, resources::gameboard, flat_)) + if (u == units_.end() || !unit_filter::matches_filter(unit_filter, *u, loc, resources::filter_con, flat_)) return false; } diff --git a/src/unit.cpp b/src/unit.cpp index 931d95fb5056..444d4a7ad8f1 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -1580,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 (!unit_filter::matches_filter(vconfig(afilter), *this, loc_, resources::gameboard)) continue; + if (!unit_filter::matches_filter(vconfig(afilter), *this, loc_, resources::filter_con)) continue; const std::string &apply_to = effect["apply_to"]; const std::string &apply_times = effect["times"]; diff --git a/src/unit_abilities.cpp b/src/unit_abilities.cpp index 8343f7c67637..c7a54357f3b8 100644 --- a/src/unit_abilities.cpp +++ b/src/unit_abilities.cpp @@ -297,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 ( !unit_filter::matches_filter(vconfig(afilter), *this, loc, resources::gameboard, illuminates) ) + if ( !unit_filter::matches_filter(vconfig(afilter), *this, loc, resources::filter_con, illuminates) ) return false; map_location adjacent[6]; @@ -315,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_filter::matches_filter(vconfig(i), *unit, unit->get_location(), resources::gameboard, illuminates)) + if (!unit_filter::matches_filter(vconfig(i), *unit, unit->get_location(), resources::filter_con, illuminates)) return false; } } @@ -353,7 +353,7 @@ bool unit::ability_affects_adjacent(const std::string& ability, const config& cf std::vector 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 ( unit_filter::matches_filter(vconfig(filter), *this, loc, resources::gameboard, illuminates) ) + if ( unit_filter::matches_filter(vconfig(filter), *this, loc, resources::filter_con, illuminates) ) return true; } else return true; @@ -371,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 unit_filter::matches_filter(vconfig(filter), *this, loc, resources::gameboard, ability == "illuminates"); + return unit_filter::matches_filter(vconfig(filter), *this, loc, resources::filter_con, ability == "illuminates"); } bool unit::has_ability_type(const std::string& ability) const @@ -794,7 +794,7 @@ namespace { // Helpers for attack_type::special_active() return true; // Check for a unit match. - if ( !un_it.valid() || !unit_filter::matches_filter(vconfig(filter_child), *un_it, loc, resources::gameboard) ) + if ( !un_it.valid() || !unit_filter::matches_filter(vconfig(filter_child), *un_it, loc, resources::filter_con) ) return false; // Check for a weapon match. @@ -884,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_filter::matches_filter(vconfig(i), *unit, adjacent[index], resources::gameboard) ) + !unit_filter::matches_filter(vconfig(i), *unit, adjacent[index], resources::filter_con) ) return false; } } diff --git a/src/unit_animation.cpp b/src/unit_animation.cpp index f8c9fa52c719..1ccb0a93116b 100644 --- a/src/unit_animation.cpp +++ b/src/unit_animation.cpp @@ -404,7 +404,7 @@ int unit_animation::matches(const display &disp, const map_location& loc,const m } std::vector::const_iterator myitor; for(myitor = unit_filter_.begin(); myitor != unit_filter_.end(); ++myitor) { - if (!unit_filter::matches_filter(vconfig(*myitor), *my_unit, loc, &disp.get_disp_context())) return MATCH_FAIL; + if (!unit_filter::matches_filter(vconfig(*myitor), *my_unit, loc, &disp)) return MATCH_FAIL; ++result; } if(!secondary_unit_filter_.empty()) { @@ -413,7 +413,7 @@ int unit_animation::matches(const display &disp, const map_location& loc,const m if (unit->get_location() == second_loc) { std::vector::const_iterator second_itor; for(second_itor = secondary_unit_filter_.begin(); second_itor != secondary_unit_filter_.end(); ++second_itor) { - if (!unit_filter::matches_filter(vconfig(*second_itor), *unit, second_loc, &disp.get_disp_context())) return MATCH_FAIL; + if (!unit_filter::matches_filter(vconfig(*second_itor), *unit, second_loc, &disp)) return MATCH_FAIL; result++; } diff --git a/src/unit_display.cpp b/src/unit_display.cpp index 4540d0bc9586..d61e5d0dfb34 100644 --- a/src/unit_display.cpp +++ b/src/unit_display.cpp @@ -774,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 ( unit_filter::matches_filter(filter, *u, resources::gameboard) ) + if ( unit_filter::matches_filter(filter, *u, resources::filter_con) ) break; } } diff --git a/src/unit_filter.cpp b/src/unit_filter.cpp index 69815554a10e..b5e5398635bc 100644 --- a/src/unit_filter.cpp +++ b/src/unit_filter.cpp @@ -17,6 +17,7 @@ #include "config.hpp" #include "display_context.hpp" +#include "filter_context.hpp" #include "map_location.hpp" #include "resources.hpp" //Needed for lua kernel pointer #include "scripting/lua.hpp" //Needed for lua kernel @@ -31,24 +32,24 @@ #include -namespace { bool internal_matches_filter(const vconfig& filter, const unit & u, const map_location& loc, const display_context * board, bool use_flat_tod); } +namespace { bool internal_matches_filter(const vconfig& filter, const unit & u, const map_location& loc, const filter_context * fc, 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& filter, const unit & u, const filter_context * fc, bool use_flat_tod) +{ return matches_filter(filter, u, u.get_location(), fc, 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_filter(const vconfig& cfg, const unit & u, const map_location& loc, const filter_context * fc, 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); + assert(fc != NULL); + scoped_xy_unit auto_store("this_unit", loc.x, loc.y, fc->get_disp_context().units()); + matches = internal_matches_filter(cfg, u, loc, fc, 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); + matches = internal_matches_filter(cfg, u, loc, fc, use_flat_tod); } // Handle [and], [or], and [not] with in-order precedence @@ -62,15 +63,15 @@ bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, // Handle [and] if(cond_name == "and") { - matches = matches && matches_filter(cond_filter,u, loc, board, use_flat_tod); + matches = matches && matches_filter(cond_filter,u, loc, fc, use_flat_tod); } // Handle [or] else if(cond_name == "or") { - matches = matches || matches_filter(cond_filter,u, loc, board,use_flat_tod); + matches = matches || matches_filter(cond_filter,u, loc, fc,use_flat_tod); } // Handle [not] else if(cond_name == "not") { - matches = matches && !matches_filter(cond_filter,u, loc, board,use_flat_tod); + matches = matches && !matches_filter(cond_filter,u, loc, fc,use_flat_tod); } ++cond; @@ -82,7 +83,7 @@ bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, 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) +bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, const filter_context * fc, bool use_flat_tod) { config::attribute_value cfg_name = cfg["name"]; if (!cfg_name.blank() && cfg_name.str() != u.name()) { @@ -114,9 +115,9 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } if(cfg.has_child("filter_location")) { - assert(board != NULL); + assert(fc != NULL); const vconfig& t_cfg = cfg.child("filter_location"); - terrain_filter t_filter(t_cfg, board->units(), use_flat_tod); + terrain_filter t_filter(t_cfg, fc->get_disp_context().units(), use_flat_tod); if(!t_filter.match(loc)) { return false; } @@ -135,8 +136,8 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat 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))) + if ((!fc && loc.valid()) || + (fc && fc->get_disp_context().map().on_board(loc))) { return false; } @@ -317,12 +318,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } config::attribute_value cfg_defense = cfg["defense"]; - if (!cfg_defense.blank() && cfg_defense.to_int(-1) != u.defense_modifier(board->map().get_terrain(loc))) { + if (!cfg_defense.blank() && cfg_defense.to_int(-1) != u.defense_modifier(fc->get_disp_context().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))) { + if (!cfg_movement.blank() && cfg_movement.to_int(-1) != u.movement_cost(fc->get_disp_context().map().get_terrain(loc))) { return false; } @@ -369,7 +370,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } std::set::const_iterator viewer, viewer_end = viewers.end(); for (viewer = viewers.begin(); viewer != viewer_end; ++viewer) { - bool fogged = board->teams()[*viewer - 1].fogged(loc); + bool fogged = fc->get_disp_context().teams()[*viewer - 1].fogged(loc); bool hiding = u.invisible(loc/*, false(?) */); bool unit_hidden = fogged || hiding; if (visible == unit_hidden) return false; @@ -378,8 +379,8 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } if (cfg.has_child("filter_adjacent")) { - assert(board); - const unit_map& units = board->units(); + assert(fc); + const unit_map& units = fc->get_disp_context().units(); map_location adjacent[6]; get_adjacent_tiles(loc, adjacent); vconfig::child_list::const_iterator i, i_end; @@ -393,12 +394,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat 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)) { + || !unit_filter::matches_filter(*i, *unit_itor, unit_itor->get_location(), fc, 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())) { + fc->get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) { ++match_count; } } diff --git a/src/unit_filter.hpp b/src/unit_filter.hpp index da337a5ce473..1d8d8b757173 100644 --- a/src/unit_filter.hpp +++ b/src/unit_filter.hpp @@ -23,17 +23,17 @@ * these to speed up repeated application of the filter. */ -class display_context; +class filter_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); + bool matches_filter(const vconfig& cfg,const unit & u, const map_location& loc, const filter_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); + bool matches_filter(const vconfig& filter, const unit & u, const filter_context* board, bool use_flat_tod=false); } From 35b23ec3214d757597948c1942de27fb7dd26ff1 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 3 Jul 2014 10:52:37 -0400 Subject: [PATCH 4/7] side_filter uses filter_context --- src/game_events/action_wml.cpp | 12 ++++---- src/game_events/pump.cpp | 2 +- src/scripting/lua.cpp | 4 +-- src/side_filter.cpp | 54 +++++++++++++++++++--------------- src/side_filter.hpp | 6 ++-- src/terrain_filter.cpp | 4 +-- src/unit_filter.cpp | 4 +-- 7 files changed, 47 insertions(+), 39 deletions(-) diff --git a/src/game_events/action_wml.cpp b/src/game_events/action_wml.cpp index 30ae50a9e428..cf8d2ec149cc 100644 --- a/src/game_events/action_wml.cpp +++ b/src/game_events/action_wml.cpp @@ -375,11 +375,11 @@ namespace { // Support functions if (!ssf.null()) { if(!sides.empty()) { WRN_NG << "ignoring duplicate side filter information (inline side=)" << std::endl; } - side_filter filter(ssf); + side_filter filter(ssf, resources::filter_con); return filter.get_teams(); } - side_filter filter(sides.str()); + side_filter filter(sides.str(), resources::filter_con); return filter.get_teams(); } @@ -444,7 +444,7 @@ namespace { // Support functions { // Filter the sides. const vconfig &ssf = cfg.child("filter_side"); - const side_filter s_filter(ssf.null() ? vconfig::empty_vconfig() : ssf); + const side_filter s_filter(ssf.null() ? vconfig::empty_vconfig() : ssf, resources::filter_con); const std::vector sides = s_filter.get_teams(); // Filter the locations. @@ -1121,10 +1121,10 @@ WML_HANDLER_FUNCTION(modify_ai, /*event_info*/, cfg) ERR_NG << "duplicate side information in [modify_ai]" << std::endl; return; } - side_filter ssf(filter_side); + side_filter ssf(filter_side, resources::filter_con); sides = ssf.get_teams(); } else { - side_filter ssf(cfg); + side_filter ssf(cfg, resources::filter_con); sides = ssf.get_teams(); } BOOST_FOREACH(const int &side_num, sides) @@ -1607,7 +1607,7 @@ WML_HANDLER_FUNCTION(redraw, /*event_info*/, cfg) } if (clear_shroud_bool) { - side_filter filter(cfg); + side_filter filter(cfg, resources::filter_con); BOOST_FOREACH(const int side, filter.get_teams()){ actions::clear_shroud(side); } diff --git a/src/game_events/pump.cpp b/src/game_events/pump.cpp index 287d7bb3cfe2..447c80a1be7b 100644 --- a/src/game_events/pump.cpp +++ b/src/game_events/pump.cpp @@ -170,7 +170,7 @@ namespace { // Support functions BOOST_FOREACH(const vconfig &f, filters.get_children("filter_side")) { - side_filter ssf(f); + side_filter ssf(f, resources::filter_con); if ( !ssf.match(resources::controller->current_side()) ) return false; } diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 75319c31f7ad..316234215ed3 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -3250,7 +3250,7 @@ static int intf_match_side(lua_State *L) return 1; } - side_filter s_filter(filter); + side_filter s_filter(filter, resources::filter_con); lua_pushboolean(L, s_filter.match(side + 1)); return 1; } @@ -3268,7 +3268,7 @@ static int intf_get_sides(lua_State* L) for(unsigned side_number = 1; side_number <= resources::teams->size(); ++side_number) sides.push_back(side_number); } else { - side_filter filter(ssf); + side_filter filter(ssf, resources::filter_con); sides = filter.get_teams(); } diff --git a/src/side_filter.cpp b/src/side_filter.cpp index e2b27b790049..a40acbd491aa 100644 --- a/src/side_filter.cpp +++ b/src/side_filter.cpp @@ -17,10 +17,10 @@ #include "global.hpp" #include "config.hpp" -#include "game_board.hpp" +#include "display_context.hpp" +#include "filter_context.hpp" #include "log.hpp" #include "recall_list_manager.hpp" -#include "resources.hpp" #include "side_filter.hpp" #include "variable.hpp" #include "team.hpp" @@ -40,10 +40,11 @@ static lg::log_domain log_engine_sf("engine/side_filter"); // and so we don't care about the warnings this quick fix generates #pragma warning(push) #pragma warning(disable:4413) -side_filter::side_filter(): - cfg_(vconfig::unconstructed_vconfig()), - flat_(), - side_string_() +side_filter::side_filter() + : cfg_(vconfig::unconstructed_vconfig()) + , flat_() + , side_string_() + , fc_(NULL) { assert(false); } @@ -51,23 +52,25 @@ side_filter::side_filter(): #endif -side_filter::side_filter(const vconfig& cfg, bool flat_tod) : - cfg_(cfg), - flat_(flat_tod), - side_string_() +side_filter::side_filter(const vconfig& cfg, const filter_context * fc, bool flat_tod) + : cfg_(cfg) + , flat_(flat_tod) + , side_string_() + , fc_(fc) { } -side_filter::side_filter(const std::string &side_string, bool flat_tod) - : cfg_(vconfig::empty_vconfig()), flat_(flat_tod), side_string_(side_string) +side_filter::side_filter(const std::string &side_string, const filter_context * fc, bool flat_tod) + : cfg_(vconfig::empty_vconfig()), flat_(flat_tod), side_string_(side_string), fc_(fc) { } std::vector side_filter::get_teams() const { + assert(fc_); //@todo: replace with better implementation std::vector result; - BOOST_FOREACH(const team &t, *resources::teams) { + BOOST_FOREACH(const team &t, fc_->get_disp_context().teams()) { if (match(t)) { result.push_back(t.side()); } @@ -91,6 +94,8 @@ static bool check_side_number(const team &t, const std::string &str) bool side_filter::match_internal(const team &t) const { + assert(fc_); + if (cfg_.has_attribute("side_in")) { if (!check_side_number(t,cfg_["side_in"])) { return false; @@ -132,11 +137,11 @@ bool side_filter::match_internal(const team &t) const if(cfg_.has_child("has_unit")) { const vconfig& unit_filter = cfg_.child("has_unit"); bool found = false; - BOOST_FOREACH(unit &u, *resources::units) { + BOOST_FOREACH(const unit &u, fc_->get_disp_context().units()) { if (u.side() != t.side()) { continue; } - if (unit_filter::matches_filter(unit_filter, u, u.get_location(), resources::filter_con, flat_)) { + if (unit_filter::matches_filter(unit_filter, u, u.get_location(), fc_, flat_)) { found = true; break; } @@ -144,7 +149,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(unit_filter::matches_filter(unit_filter, *u, u->get_location(), resources::filter_con, flat_)) { + if(unit_filter::matches_filter(unit_filter, *u, u->get_location(), fc_, flat_)) { found = true; break; } @@ -157,22 +162,22 @@ bool side_filter::match_internal(const team &t) const const vconfig& enemy_of = cfg_.child("enemy_of"); if(!enemy_of.null()) { - side_filter s_filter(enemy_of); + side_filter s_filter(enemy_of, fc_); const std::vector& teams = s_filter.get_teams(); if(teams.empty()) return false; BOOST_FOREACH(const int side, teams) { - if(!(*resources::teams)[side - 1].is_enemy(t.side())) + if(!(fc_->get_disp_context().teams())[side - 1].is_enemy(t.side())) return false; } } const vconfig& allied_with = cfg_.child("allied_with"); if(!allied_with.null()) { - side_filter s_filter(allied_with); + side_filter s_filter(allied_with, fc_); const std::vector& teams = s_filter.get_teams(); if(teams.empty()) return false; BOOST_FOREACH(const int side, teams) { - if((*resources::teams)[side - 1].is_enemy(t.side())) + if((fc_->get_disp_context().teams())[side - 1].is_enemy(t.side())) return false; } } @@ -194,7 +199,8 @@ bool side_filter::match_internal(const team &t) const bool side_filter::match(int side) const { - return this->match((*resources::teams)[side-1]); + assert(fc_); + return this->match((fc_->get_disp_context().teams())[side-1]); } bool side_filter::match(const team& t) const @@ -211,17 +217,17 @@ bool side_filter::match(const team& t) const //handle [and] if(cond_name == "and") { - matches = matches && side_filter(cond_cfg, flat_).match(t); + matches = matches && side_filter(cond_cfg, fc_, flat_).match(t); } //handle [or] else if(cond_name == "or") { - matches = matches || side_filter(cond_cfg, flat_).match(t); + matches = matches || side_filter(cond_cfg, fc_, flat_).match(t); } //handle [not] else if(cond_name == "not") { - matches = matches && !side_filter(cond_cfg, flat_).match(t); + matches = matches && !side_filter(cond_cfg, fc_, flat_).match(t); } ++cond; } diff --git a/src/side_filter.hpp b/src/side_filter.hpp index 76309728a3c8..40245976f563 100644 --- a/src/side_filter.hpp +++ b/src/side_filter.hpp @@ -18,6 +18,7 @@ #include "variable.hpp" class config; +class filter_context; class unit; class unit_map; class team; @@ -35,8 +36,8 @@ class side_filter { side_filter(); #endif - side_filter(const std::string &side_string, bool flat_tod = false); - side_filter(const vconfig &cfg, bool flat_tod = false); + side_filter(const std::string &side_string, const filter_context * fc, bool flat_tod = false); + side_filter(const vconfig &cfg, const filter_context * fc, bool flat_tod = false); //match: returns true if and only if the given team matches this filter bool match(const team& t) const; @@ -54,6 +55,7 @@ class side_filter { bool flat_; std::string side_string_; + const filter_context * fc_; //!< The filter context for this filter. It should be a pointer because otherwise the default ctor doesn't work }; #endif diff --git a/src/terrain_filter.cpp b/src/terrain_filter.cpp index 3310ac32e426..d8c05221adc1 100644 --- a/src/terrain_filter.cpp +++ b/src/terrain_filter.cpp @@ -166,7 +166,7 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x bool visible = (*i)["visible"].to_bool(true); bool respect_fog = (*i)["respect_fog"].to_bool(true); - side_filter ssf(*i); + side_filter ssf(*i, resources::filter_con); std::vector sides = ssf.get_teams(); BOOST_FOREACH(const int side, sides) { @@ -287,7 +287,7 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x } if(!resources::gameboard->map().is_village(loc)) return false; - side_filter ssf(filter_owner); + side_filter ssf(filter_owner, resources::filter_con); const std::vector& sides = ssf.get_teams(); bool found = false; if(sides.empty() && resources::gameboard->village_owner(loc) == -1) diff --git a/src/unit_filter.cpp b/src/unit_filter.cpp index b5e5398635bc..488d5e5b754a 100644 --- a/src/unit_filter.cpp +++ b/src/unit_filter.cpp @@ -125,7 +125,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat const vconfig& filter_side = cfg.child("filter_side"); if(!filter_side.null()) { - side_filter s_filter(filter_side); + side_filter s_filter(filter_side, fc); if(!s_filter.match(u.side())) return false; } @@ -362,7 +362,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat bool visible = (*i)["visible"].to_bool(true); std::set viewers; // Use standard side filter - side_filter ssf(*i); + side_filter ssf(*i, fc); std::vector sides = ssf.get_teams(); viewers.insert(sides.begin(), sides.end()); if (viewers.empty()) { From 18159f0a6b4056ff4609ee4dcc8be4ff0018494f Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 3 Jul 2014 11:34:00 -0400 Subject: [PATCH 5/7] terrain_filter uses filter_context instead of resources --- src/ai/composite/goal.cpp | 5 +- src/ai/composite/value_translator.hpp | 6 +-- src/ai/contexts.cpp | 2 +- src/ai/lua/lua_object.hpp | 2 +- src/game_events/action_wml.cpp | 6 +-- src/game_events/conditional_wml.cpp | 2 +- src/game_events/menu_item.cpp | 2 +- src/pathfind/teleport.cpp | 4 +- src/scripting/lua.cpp | 9 ++-- src/terrain_filter.cpp | 73 ++++++++++++++------------- src/terrain_filter.hpp | 5 +- src/unit_abilities.cpp | 4 +- src/unit_display.cpp | 2 +- src/unit_filter.cpp | 2 +- 14 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/ai/composite/goal.cpp b/src/ai/composite/goal.cpp index c8f24263afb9..b8e39eeac279 100644 --- a/src/ai/composite/goal.cpp +++ b/src/ai/composite/goal.cpp @@ -24,6 +24,7 @@ #include "ai/lua/core.hpp" #include "ai/lua/lua_object.hpp" #include "ai/manager.hpp" +#include "filter_context.hpp" #include "game_board.hpp" #include "log.hpp" #include "map_location.hpp" @@ -165,7 +166,7 @@ void target_location_goal::on_create() } const config &criteria = cfg_.child("criteria"); if (criteria) { - filter_ptr_ = boost::shared_ptr(new terrain_filter(vconfig(criteria),*resources::units)); + filter_ptr_ = boost::shared_ptr(new terrain_filter(vconfig(criteria),resources::filter_con)); } } @@ -221,7 +222,7 @@ void protect_goal::on_create() } const config &criteria = cfg_.child("criteria"); if (criteria) { - filter_ptr_ = boost::shared_ptr(new terrain_filter(vconfig(criteria),*resources::units)); + filter_ptr_ = boost::shared_ptr(new terrain_filter(vconfig(criteria),resources::filter_con)); } diff --git a/src/ai/composite/value_translator.hpp b/src/ai/composite/value_translator.hpp index 8a72c690b8f4..b66703e30402 100644 --- a/src/ai/composite/value_translator.hpp +++ b/src/ai/composite/value_translator.hpp @@ -179,10 +179,10 @@ class config_value_translator { static terrain_filter cfg_to_value(const config &cfg) { if (const config &v = cfg.child("value")) { - return terrain_filter(vconfig(v), *resources::units); + return terrain_filter(vconfig(v), resources::filter_con); } static config c("not"); - return terrain_filter(vconfig(c),*resources::units); + return terrain_filter(vconfig(c),resources::filter_con); } static void cfg_to_value(const config &cfg, terrain_filter &value) @@ -442,7 +442,7 @@ class variant_value_translator { static terrain_filter variant_to_value(const variant &var) { static config c("not"); - terrain_filter value(vconfig(c),*resources::units); + terrain_filter value(vconfig(c),resources::filter_con); variant_to_value(var,value); return value; } diff --git a/src/ai/contexts.cpp b/src/ai/contexts.cpp index 809bbe4e281a..2e0b96b6cc36 100644 --- a/src/ai/contexts.cpp +++ b/src/ai/contexts.cpp @@ -608,7 +608,7 @@ const terrain_filter& readonly_context_impl::get_avoid() const } config cfg; cfg.add_child("not"); - static terrain_filter tf(vconfig(cfg),*resources::units); + static terrain_filter tf(vconfig(cfg),resources::filter_con); return tf; } diff --git a/src/ai/lua/lua_object.hpp b/src/ai/lua/lua_object.hpp index d6385e83c9d8..87947c225325 100644 --- a/src/ai/lua/lua_object.hpp +++ b/src/ai/lua/lua_object.hpp @@ -138,7 +138,7 @@ inline boost::shared_ptr lua_object::to_type(lua boost::shared_ptr cfg = boost::shared_ptr(new config()); boost::shared_ptr vcfg = boost::shared_ptr(new vconfig(*cfg)); luaW_tovconfig(L, n, *vcfg); - boost::shared_ptr tf = boost::shared_ptr(new terrain_filter(*vcfg, *resources::units)); + boost::shared_ptr tf = boost::shared_ptr(new terrain_filter(*vcfg, resources::filter_con)); return tf; } diff --git a/src/game_events/action_wml.cpp b/src/game_events/action_wml.cpp index cf8d2ec149cc..0c225c7b1a3e 100644 --- a/src/game_events/action_wml.cpp +++ b/src/game_events/action_wml.cpp @@ -449,7 +449,7 @@ namespace { // Support functions // Filter the locations. std::set locs; - const terrain_filter t_filter(cfg, *resources::units); + const terrain_filter t_filter(cfg, resources::filter_con); t_filter.get_locations(locs, true); // Loop through sides. @@ -485,7 +485,7 @@ namespace { // Support functions // Filter the locations. std::set locs; - const terrain_filter filter(cfg, *resources::units); + const terrain_filter filter(cfg, resources::filter_con); filter.get_locations(locs, true); BOOST_FOREACH(const int &side_num, sides) @@ -2398,7 +2398,7 @@ WML_HANDLER_FUNCTION(time_area, /*event_info*/, cfg) id = ids; } std::set locs; - const terrain_filter filter(cfg, *resources::units); + const terrain_filter filter(cfg, resources::filter_con); filter.get_locations(locs, true); config parsed_cfg = cfg.get_parsed_config(); resources::tod_manager->add_time_area(id, locs, parsed_cfg); diff --git a/src/game_events/conditional_wml.cpp b/src/game_events/conditional_wml.cpp index ba41a0a09287..249b94e34031 100644 --- a/src/game_events/conditional_wml.cpp +++ b/src/game_events/conditional_wml.cpp @@ -114,7 +114,7 @@ namespace { // Support functions backwards_compat = backwards_compat && have_location.empty(); for(vconfig::child_list::const_iterator v = have_location.begin(); v != have_location.end(); ++v) { std::set res; - terrain_filter(*v, *resources::units).get_locations(res); + terrain_filter(*v, resources::filter_con).get_locations(res); std::vector > counts = (*v).has_attribute("count") ? utils::parse_ranges((*v)["count"]) : default_counts; diff --git a/src/game_events/menu_item.cpp b/src/game_events/menu_item.cpp index 0f1bcbb3ac54..c3cc7919fe80 100644 --- a/src/game_events/menu_item.cpp +++ b/src/game_events/menu_item.cpp @@ -171,7 +171,7 @@ bool wml_menu_item::can_show(const map_location & hex) const // Failing the [fiter_location] tag means no show. if ( !filter_location_.empty() && - !terrain_filter(filter_location_, *resources::units)(hex) ) + !terrain_filter(filter_location_, resources::filter_con)(hex) ) return false; // Failing to have a required selection means no show. diff --git a/src/pathfind/teleport.cpp b/src/pathfind/teleport.cpp index d4fdefac3fad..aef34495cd1b 100644 --- a/src/pathfind/teleport.cpp +++ b/src/pathfind/teleport.cpp @@ -80,10 +80,10 @@ void teleport_group::get_teleport_pair( scoped_xy_unit teleport_unit("teleport_unit", loc.x, loc.y, *resources::units); - terrain_filter source_filter(source, *units); + terrain_filter source_filter(source, resources::filter_con); source_filter.get_locations(reversed_ ? loc_pair.second : loc_pair.first); - terrain_filter target_filter(target, *units); + terrain_filter target_filter(target, resources::filter_con); target_filter.get_locations(reversed_ ? loc_pair.first : loc_pair.second); } } diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 316234215ed3..4cfb15b7dde9 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -41,6 +41,7 @@ #include "config.hpp" // for config, etc #include "display_chat_manager.hpp" // for clear_chat_messages #include "filesystem.hpp" // for get_wml_location +#include "filter_context.hpp" #include "font.hpp" // for LABEL_COLOR #include "game_board.hpp" // for game_board #include "game_classification.hpp" // for game_classification, etc @@ -2119,7 +2120,7 @@ static int intf_find_cost_map(lua_State *L) { filter = vconfig(config(), true); } - const terrain_filter t_filter(filter, *resources::units); + const terrain_filter t_filter(filter, resources::filter_con); t_filter.get_locations(location_set, true); ++arg; @@ -3163,7 +3164,7 @@ static int intf_get_locations(lua_State *L) vconfig filter = luaW_checkvconfig(L, 1); std::set res; - const terrain_filter t_filter(filter, *resources::units); + const terrain_filter t_filter(filter, resources::filter_con); t_filter.get_locations(res, true); lua_createtable(L, res.size(), 0); @@ -3195,7 +3196,7 @@ static int intf_get_villages(lua_State *L) vconfig filter = luaW_checkvconfig(L, 1); for(std::vector::const_iterator it = locs.begin(); it != locs.end(); ++it) { - bool matches = terrain_filter(filter, *resources::units).match(*it); + bool matches = terrain_filter(filter, resources::filter_con).match(*it); if (matches) { lua_createtable(L, 2, 0); lua_pushinteger(L, it->x + 1); @@ -3226,7 +3227,7 @@ static int intf_match_location(lua_State *L) return 1; } - const terrain_filter t_filter(filter, *resources::units); + const terrain_filter t_filter(filter, resources::filter_con); lua_pushboolean(L, t_filter.match(map_location(x, y))); return 1; } diff --git a/src/terrain_filter.cpp b/src/terrain_filter.cpp index d8c05221adc1..3a429425ff89 100644 --- a/src/terrain_filter.cpp +++ b/src/terrain_filter.cpp @@ -17,10 +17,11 @@ #include "global.hpp" #include "config.hpp" +#include "display_context.hpp" +#include "filter_context.hpp" #include "game_board.hpp" #include "log.hpp" #include "map.hpp" -#include "resources.hpp" #include "side_filter.hpp" #include "team.hpp" #include "terrain_filter.hpp" @@ -46,7 +47,7 @@ terrain_filter::~terrain_filter() #pragma warning(disable:4413) terrain_filter::terrain_filter(): cfg_(vconfig::unconstructed_vconfig()), - units_(unit_map()), + fc_(NULL), cache_(), max_loop_(), flat_() @@ -57,10 +58,10 @@ terrain_filter::terrain_filter(): #endif -terrain_filter::terrain_filter(const vconfig& cfg, const unit_map& units, +terrain_filter::terrain_filter(const vconfig& cfg, const filter_context * fc, const bool flat_tod, const size_t max_loop) : cfg_(cfg), - units_(units), + fc_(fc), cache_(), max_loop_(max_loop), flat_(flat_tod) @@ -69,7 +70,7 @@ terrain_filter::terrain_filter(const vconfig& cfg, const unit_map& units, terrain_filter::terrain_filter(const vconfig& cfg, const terrain_filter& original) : cfg_(cfg), - units_(original.units_), + fc_(original.fc_), cache_(), max_loop_(original.max_loop_), flat_(original.flat_) @@ -80,7 +81,7 @@ terrain_filter::terrain_filter(const terrain_filter& other) : xy_pred(), // We should construct this too, since it has no datamembers // use the default constructor. cfg_(other.cfg_), - units_(other.units_), + fc_(other.fc_), cache_(), max_loop_(other.max_loop_), flat_(other.flat_) @@ -109,7 +110,7 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x { //Filter Areas if (cfg_.has_attribute("area") && - resources::tod_manager->get_area_by_id(cfg_["area"]).count(loc) == 0) + fc_->get_tod_man().get_area_by_id(cfg_["area"]).count(loc) == 0) return false; if(cfg_.has_attribute("terrain")) { @@ -117,7 +118,7 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x cache_.parsed_terrain = new t_translation::t_match(cfg_["terrain"]); } if(!cache_.parsed_terrain->is_empty) { - const t_translation::t_terrain letter = resources::gameboard->map().get_terrain_info(loc).number(); + const t_translation::t_terrain letter = fc_->get_disp_context().map().get_terrain_info(loc).number(); if(!t_translation::terrain_matches(letter, *cache_.parsed_terrain)) { return false; } @@ -153,8 +154,8 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x //Allow filtering on unit 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() || !unit_filter::matches_filter(unit_filter, *u, loc, resources::filter_con, flat_)) + const unit_map::const_iterator u = fc_->get_disp_context().units().find(loc); + if (u == fc_->get_disp_context().units().end() || !unit_filter::matches_filter(unit_filter, *u, loc, fc_, flat_)) return false; } @@ -166,11 +167,11 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x bool visible = (*i)["visible"].to_bool(true); bool respect_fog = (*i)["respect_fog"].to_bool(true); - side_filter ssf(*i, resources::filter_con); + side_filter ssf(*i, fc_); std::vector sides = ssf.get_teams(); BOOST_FOREACH(const int side, sides) { - const team &viewing_team = resources::teams->at(side - 1); + const team &viewing_team = fc_->get_disp_context().teams().at(side - 1); bool viewer_sees = respect_fog ? !viewing_team.fogged(loc) : !viewing_team.shrouded(loc); if (visible != viewer_sees) { return false; @@ -193,7 +194,7 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x std::vector::const_iterator j, j_end = dirs.end(); for (j = dirs.begin(); j != j_end; ++j) { map_location &adj = adjacent[*j]; - if (resources::gameboard->map().on_board(adj)) { + if (fc_->get_disp_context().map().on_board(adj)) { if(cache_.adjacent_matches == NULL) { while(index >= std::distance(cache_.adjacent_match_cache.begin(), cache_.adjacent_match_cache.end())) { const vconfig& adj_cfg = adj_cfgs[cache_.adjacent_match_cache.size()]; @@ -242,9 +243,9 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x time_of_day tod; if(flat_) { - tod = resources::tod_manager->get_time_of_day(loc); + tod = fc_->get_tod_man().get_time_of_day(loc); } else { - tod = resources::tod_manager->get_illuminated_time_of_day(resources::gameboard->units(), resources::gameboard->map(),loc); + tod = fc_->get_tod_man().get_illuminated_time_of_day(fc_->get_disp_context().units(), fc_->get_disp_context().map(),loc); } if(!tod_type.empty()) { @@ -285,15 +286,15 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x if(!owner_side.empty()) { WRN_NG << "duplicate side information in a SLF, ignoring inline owner_side=" << std::endl; } - if(!resources::gameboard->map().is_village(loc)) + if(!fc_->get_disp_context().map().is_village(loc)) return false; - side_filter ssf(filter_owner, resources::filter_con); + side_filter ssf(filter_owner, fc_); const std::vector& sides = ssf.get_teams(); bool found = false; - if(sides.empty() && resources::gameboard->village_owner(loc) == -1) + if(sides.empty() && fc_->get_disp_context().village_owner(loc) == -1) found = true; BOOST_FOREACH(const int side, sides) { - if(resources::teams->at(side - 1).owns_village(loc)) { + if(fc_->get_disp_context().teams().at(side - 1).owns_village(loc)) { found = true; break; } @@ -303,7 +304,7 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x } else if(!owner_side.empty()) { const int side_index = owner_side.to_int(0) - 1; - if(resources::gameboard->village_owner(loc) != side_index) { + if(fc_->get_disp_context().village_owner(loc) != side_index) { return false; } } @@ -314,7 +315,7 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x bool terrain_filter::match(const map_location& loc) const { if(cfg_["x"] == "recall" && cfg_["y"] == "recall") { - return !resources::gameboard->map().on_board(loc); + return !fc_->get_disp_context().map().on_board(loc); } std::set hexes; std::vector loc_vec(1, loc); @@ -330,9 +331,9 @@ bool terrain_filter::match(const map_location& loc) const hexes.insert(loc_vec.begin(), loc_vec.end()); else if ( cfg_.has_child("filter_radius") ) { terrain_filter r_filter(cfg_.child("filter_radius"), *this); - get_tiles_radius(resources::gameboard->map(), loc_vec, radius, hexes, false, r_filter); + get_tiles_radius(fc_->get_disp_context().map(), loc_vec, radius, hexes, false, r_filter); } else { - get_tiles_radius(resources::gameboard->map(), loc_vec, radius, hexes); + get_tiles_radius(fc_->get_disp_context().map(), loc_vec, radius, hexes); } size_t loop_count = 0; @@ -390,9 +391,9 @@ void terrain_filter::get_locations(std::set& locs, bool with_borde && !cfg_.has_attribute("area") ) { //consider all locations on the map - int bs = resources::gameboard->map().border_size(); - int w = with_border ? resources::gameboard->map().w() + bs : resources::gameboard->map().w(); - int h = with_border ? resources::gameboard->map().h() + bs : resources::gameboard->map().h(); + int bs = fc_->get_disp_context().map().border_size(); + int w = with_border ? fc_->get_disp_context().map().w() + bs : fc_->get_disp_context().map().w(); + int h = with_border ? fc_->get_disp_context().map().h() + bs : fc_->get_disp_context().map().h(); for (int x = with_border ? 0 - bs : 0; x < w; ++x) { for (int y = with_border ? 0 - bs : 0; y < h; ++y) { match_set.insert(map_location(x,y)); @@ -406,7 +407,7 @@ void terrain_filter::get_locations(std::set& locs, bool with_borde && !cfg_.has_attribute("area") ) { std::vector xy_vector; - xy_vector = resources::gameboard->map().parse_location_range(cfg_["x"], cfg_["y"], with_border); + xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border); match_set.insert(xy_vector.begin(), xy_vector.end()); } else @@ -435,7 +436,7 @@ void terrain_filter::get_locations(std::set& locs, bool with_borde && !cfg_.has_attribute("find_in") && cfg_.has_attribute("area") ) { - const std::set& area = resources::tod_manager->get_area_by_id(cfg_["area"]); + const std::set& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]); match_set.insert(area.begin(), area.end()); } else @@ -445,7 +446,7 @@ void terrain_filter::get_locations(std::set& locs, bool with_borde && !cfg_.has_attribute("area") ) { std::vector xy_vector; - xy_vector = resources::gameboard->map().parse_location_range(cfg_["x"], cfg_["y"], with_border); + xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border); match_set.insert(xy_vector.begin(), xy_vector.end()); // remove any locations not found in the specified variable @@ -478,8 +479,8 @@ void terrain_filter::get_locations(std::set& locs, bool with_borde && cfg_.has_attribute("area") ) { std::vector xy_vector; - xy_vector = resources::gameboard->map().parse_location_range(cfg_["x"], cfg_["y"], with_border); - const std::set& area = resources::tod_manager->get_area_by_id(cfg_["area"]); + xy_vector = fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border); + const std::set& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]); BOOST_FOREACH(const map_location& loc, xy_vector) { if (area.count(loc) != 0) @@ -492,7 +493,7 @@ void terrain_filter::get_locations(std::set& locs, bool with_borde && cfg_.has_attribute("find_in") && cfg_.has_attribute("area") ) { - const std::set& area = resources::tod_manager->get_area_by_id(cfg_["area"]); + const std::set& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]); //use content of find_in as starting set variable_info vi(cfg_["find_in"], false, variable_info::TYPE_CONTAINER); @@ -517,10 +518,10 @@ void terrain_filter::get_locations(std::set& locs, bool with_borde && cfg_.has_attribute("area") ) { const std::vector& xy_vector = - resources::gameboard->map().parse_location_range(cfg_["x"], cfg_["y"], with_border); + fc_->get_disp_context().map().parse_location_range(cfg_["x"], cfg_["y"], with_border); std::set xy_set(xy_vector.begin(), xy_vector.end()); - const std::set& area = resources::tod_manager->get_area_by_id(cfg_["area"]); + const std::set& area = fc_->get_tod_man().get_area_by_id(cfg_["area"]); //use content of find_in as starting set variable_info vi(cfg_["find_in"], false, variable_info::TYPE_CONTAINER); @@ -630,9 +631,9 @@ void terrain_filter::get_locations(std::set& locs, bool with_borde std::vector xy_vector (match_set.begin(), match_set.end()); if(cfg_.has_child("filter_radius")) { terrain_filter r_filter(cfg_.child("filter_radius"), *this); - get_tiles_radius(resources::gameboard->map(), xy_vector, radius, locs, with_border, r_filter); + get_tiles_radius(fc_->get_disp_context().map(), xy_vector, radius, locs, with_border, r_filter); } else { - get_tiles_radius(resources::gameboard->map(), xy_vector, radius, locs, with_border); + get_tiles_radius(fc_->get_disp_context().map(), xy_vector, radius, locs, with_border); } } else { locs.insert(match_set.begin(), match_set.end()); diff --git a/src/terrain_filter.hpp b/src/terrain_filter.hpp index 864c3b2429c2..3f3039cbb92e 100644 --- a/src/terrain_filter.hpp +++ b/src/terrain_filter.hpp @@ -21,6 +21,7 @@ #include "variable.hpp" class config; +class filter_context; class unit; class unit_map; class team; @@ -37,7 +38,7 @@ class terrain_filter : public xy_pred { #endif terrain_filter(const vconfig& cfg, - const unit_map& units, const bool flat_tod=false, const size_t max_loop=game_config::max_loop); + const filter_context * fc, const bool flat_tod=false, const size_t max_loop=game_config::max_loop); terrain_filter(const vconfig& cfg, const terrain_filter& original); /** Default implementation, but defined out-of-line for efficiency reasons. */ ~terrain_filter(); @@ -66,7 +67,7 @@ class terrain_filter : public xy_pred { bool match_internal(const map_location& loc, const bool ignore_xy) const; const vconfig cfg_; //config contains WML for a Standard Location Filter - const unit_map& units_; + const filter_context * fc_; struct terrain_filter_cache { terrain_filter_cache() : diff --git a/src/unit_abilities.cpp b/src/unit_abilities.cpp index c7a54357f3b8..7a02686f3104 100644 --- a/src/unit_abilities.cpp +++ b/src/unit_abilities.cpp @@ -328,7 +328,7 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map if (index == map_location::NDIRECTIONS) { continue; } - terrain_filter adj_filter(vconfig(i), units); + terrain_filter adj_filter(vconfig(i), resources::filter_con); adj_filter.flatten(illuminates); if(!adj_filter.match(adjacent[index])) { return false; @@ -898,7 +898,7 @@ bool attack_type::special_active(const config& special, AFFECTS whom, map_location::parse_direction(j); if (index == map_location::NDIRECTIONS) continue; - terrain_filter adj_filter(vconfig(i), units); + terrain_filter adj_filter(vconfig(i), resources::filter_con); if(!adj_filter.match(adjacent[index])) { return false; } diff --git a/src/unit_display.cpp b/src/unit_display.cpp index d61e5d0dfb34..1a46437d3a5b 100644 --- a/src/unit_display.cpp +++ b/src/unit_display.cpp @@ -827,7 +827,7 @@ void wml_animation_internal(unit_animator &animator, const vconfig &cfg, const m vconfig t_filter = cfg.child("facing"); map_location secondary_loc = map_location::null_location(); if(!t_filter.empty()) { - terrain_filter filter(t_filter, *resources::units); + terrain_filter filter(t_filter, resources::filter_con); std::set locs; filter.get_locations(locs); if (!locs.empty() && u->get_location() != *locs.begin()) { diff --git a/src/unit_filter.cpp b/src/unit_filter.cpp index 488d5e5b754a..492c4f105e97 100644 --- a/src/unit_filter.cpp +++ b/src/unit_filter.cpp @@ -117,7 +117,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat if(cfg.has_child("filter_location")) { assert(fc != NULL); const vconfig& t_cfg = cfg.child("filter_location"); - terrain_filter t_filter(t_cfg, fc->get_disp_context().units(), use_flat_tod); + terrain_filter t_filter(t_cfg, fc, use_flat_tod); if(!t_filter.match(loc)) { return false; } From 383046b469b9d53c3583f7748672a3d2a84f8198 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 3 Jul 2014 14:39:08 -0400 Subject: [PATCH 6/7] replace unit filter with a function object This allows us to separate the parsing of the filter from its invocation, similar to the side filter and terrain filter, and can speed things up if we move it outside of key loops --- src/actions/create.cpp | 14 +-- src/ai/composite/goal.cpp | 6 +- src/ai/recruitment/recruitment.cpp | 8 +- src/ai/testing/aspect_attacks.cpp | 38 +++---- src/game_events/action_wml.cpp | 44 +++++--- src/game_events/conditional_wml.cpp | 6 +- src/game_events/entity_location.cpp | 3 +- src/pathfind/teleport.cpp | 3 +- src/scripting/lua.cpp | 13 ++- src/side_filter.cpp | 9 +- src/terrain_filter.cpp | 4 +- src/unit.cpp | 2 +- src/unit_abilities.cpp | 19 ++-- src/unit_animation.cpp | 4 +- src/unit_display.cpp | 3 +- src/unit_filter.cpp | 162 +++++++++++++++++----------- src/unit_filter.hpp | 28 ++++- 17 files changed, 219 insertions(+), 147 deletions(-) diff --git a/src/actions/create.cpp b/src/actions/create.cpp index 530865bce6ef..6e8819c77b61 100644 --- a/src/actions/create.cpp +++ b/src/actions/create.cpp @@ -431,11 +431,8 @@ 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())); - const vconfig & rfilter = vconfig(leader->recall_filter()); - if ( unit_filter::matches_filter( rfilter, - recall_unit, - map_location::null_location(), - resources::filter_con) ) + const unit_filter ufilt(vconfig(leader->recall_filter()), resources::filter_con); + if ( ufilt(recall_unit, map_location::null_location()) ) { result.push_back(recall_unit_ptr); if ( already_added != NULL ) @@ -534,11 +531,8 @@ namespace { // Helpers for check_recall_location() scoped_recall_unit this_unit("this_unit", recall_team.save_id(), recall_team.recall_list().find_index(recall_unit.id())); - const vconfig & rfilter = vconfig(recaller.recall_filter()); - if ( !unit_filter::matches_filter(rfilter, - recall_unit, - map_location::null_location(), - resources::filter_con) ) + const unit_filter ufilt(vconfig(recaller.recall_filter()), resources::filter_con); + if ( !ufilt(recall_unit, map_location::null_location()) ) return RECRUIT_NO_ABLE_LEADER; // Make sure the unit is on a keep. diff --git a/src/ai/composite/goal.cpp b/src/ai/composite/goal.cpp index b8e39eeac279..d3f1399ba484 100644 --- a/src/ai/composite/goal.cpp +++ b/src/ai/composite/goal.cpp @@ -135,8 +135,9 @@ void target_unit_goal::add_targets(std::back_insert_iterator< std::vector< targe if (!criteria) return; //find the enemy leaders and explicit targets + const unit_filter ufilt(vconfig(criteria), resources::filter_con); BOOST_FOREACH(const unit &u, *resources::units) { - if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::filter_con)) { + if (ufilt( u )) { LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value() << "\n"; *target_list = target(u.get_location(), value(), target::EXPLICIT); } @@ -259,13 +260,14 @@ void protect_goal::add_targets(std::back_insert_iterator< std::vector< target > std::set items; if (protect_unit_) { + const unit_filter ufilt(vconfig(criteria), resources::filter_con); BOOST_FOREACH(const unit &u, units) { if (protect_only_own_unit_ && u.side() != get_side()) { continue; } //TODO: we will protect hidden units, by not testing for invisibility to current side - if (unit_filter::matches_filter(vconfig(criteria), u, u.get_location(), resources::filter_con)) { + if (ufilt(u)) { DBG_AI_GOAL << "side " << get_side() << ": in " << goal_type << ": " << u.get_location() << " should be protected\n"; items.insert(u.get_location()); } diff --git a/src/ai/recruitment/recruitment.cpp b/src/ai/recruitment/recruitment.cpp index 0df705509762..38e24080648b 100644 --- a/src/ai/recruitment/recruitment.cpp +++ b/src/ai/recruitment/recruitment.cpp @@ -252,8 +252,8 @@ void recruitment::execute() { // we'll check if we can do a recall instead of a recruitment. 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 (!unit_filter::matches_filter(filter, *recall, map_location::null_location(), resources::filter_con)) { + const unit_filter ufilt( vconfig(leader->recall_filter()), resources::filter_con); + if (!ufilt(*recall, map_location::null_location())) { continue; } data.recruits.insert(recall->type_id()); @@ -477,8 +477,8 @@ const std::string* recruitment::get_appropriate_recall(const std::string& type, continue; } // Check if this leader is allowed to recall this unit. - vconfig filter = vconfig(leader_data.leader->recall_filter()); - if (!unit_filter::matches_filter(filter, *recall_unit, map_location::null_location(), resources::filter_con)) { + const unit_filter ufilt(vconfig(leader_data.leader->recall_filter()), resources::filter_con); + if (!ufilt(*recall_unit, map_location::null_location())) { LOG_AI_RECRUITMENT << "Refused recall because of filter: " << recall_unit->id() << "\n"; continue; } diff --git a/src/ai/testing/aspect_attacks.cpp b/src/ai/testing/aspect_attacks.cpp index 0571864211dd..0b7741a5bfa2 100644 --- a/src/ai/testing/aspect_attacks.cpp +++ b/src/ai/testing/aspect_attacks.cpp @@ -74,9 +74,10 @@ boost::shared_ptr aspect_attacks::analyze_targets() const unit_map& units_ = *resources::units; std::vector unit_locs; + const unit_filter filt_own(vconfig(filter_own_), resources::filter_con); 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 (!unit_filter::matches_filter(vconfig(filter_own_), *i, i->get_location(), resources::filter_con)) { + if (!filt_own(*i)) { continue; } unit_locs.push_back(i->get_location()); @@ -92,25 +93,26 @@ boost::shared_ptr aspect_attacks::analyze_targets() const unit_stats_cache().clear(); + const unit_filter filt_en(vconfig(filter_enemy_), resources::filter_con); for(unit_map::const_iterator j = units_.begin(); j != units_.end(); ++j) { - // Attack anyone who is on the enemy side, - // and who is not invisible or petrified. - if (current_team().is_enemy(j->side()) && !j->incapacitated() && - !j->invisible(j->get_location())) - { - if (!unit_filter::matches_filter(vconfig(filter_enemy_), *j, j->get_location(), resources::filter_con)) { - continue; - } - map_location adjacent[6]; - get_adjacent_tiles(j->get_location(), adjacent); - attack_analysis analysis; - analysis.target = j->get_location(); - analysis.vulnerability = 0.0; - analysis.support = 0.0; - do_attack_analysis(j->get_location(), srcdst, dstsrc, - fullmove_srcdst, fullmove_dstsrc, enemy_srcdst, enemy_dstsrc, - adjacent,used_locations,unit_locs,*res,analysis, current_team()); + // Attack anyone who is on the enemy side, + // and who is not invisible or petrified. + if (current_team().is_enemy(j->side()) && !j->incapacitated() && + !j->invisible(j->get_location())) + { + if (!filt_en( *j)) { + continue; + } + map_location adjacent[6]; + get_adjacent_tiles(j->get_location(), adjacent); + attack_analysis analysis; + analysis.target = j->get_location(); + analysis.vulnerability = 0.0; + analysis.support = 0.0; + do_attack_analysis(j->get_location(), srcdst, dstsrc, + fullmove_srcdst, fullmove_dstsrc, enemy_srcdst, enemy_dstsrc, + adjacent,used_locations,unit_locs,*res,analysis, current_team()); } } return res; diff --git a/src/game_events/action_wml.cpp b/src/game_events/action_wml.cpp index 0c225c7b1a3e..8eeebd04606d 100644 --- a/src/game_events/action_wml.cpp +++ b/src/game_events/action_wml.cpp @@ -405,8 +405,9 @@ namespace { // Support functions } else if(speaker_str == "second_unit") { speaker = units->find(event_info.loc2); } else if(speaker_str != "narrator") { + const unit_filter ufilt(cfg, resources::filter_con); for(speaker = units->begin(); speaker != units->end(); ++speaker){ - if ( unit_filter::matches_filter(cfg,*speaker, resources::filter_con) ) + if ( ufilt(*speaker) ) break; } } @@ -778,8 +779,9 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg) const vconfig & healers_filter = cfg.child("filter_second"); std::vector healers; if (!healers_filter.null()) { + const unit_filter ufilt(healers_filter, resources::filter_con); BOOST_FOREACH(unit& u, *units) { - if ( unit_filter::matches_filter(healers_filter,u, resources::filter_con) && u.has_ability_type("heals") ) { + if ( ufilt(u) && u.has_ability_type("heals") ) { healers.push_back(&u); } } @@ -794,13 +796,15 @@ WML_HANDLER_FUNCTION(heal_unit, event_info, cfg) const vconfig & healed_filter = cfg.child("filter"); bool only_unit_at_loc1 = healed_filter.null(); bool heal_amount_to_set = true; + + const unit_filter ufilt(healed_filter, resources::filter_con); for(unit_map::unit_iterator u = units->begin(); u != units->end(); ++u) { if (only_unit_at_loc1) { u = units->find(event_info.loc1); if(!u.valid()) return; } - else if ( !unit_filter::matches_filter(healed_filter,*u, resources::filter_con) ) continue; + else if ( !ufilt(*u) ) continue; int heal_amount = u->max_hitpoints() - u->hitpoints(); if(amount.blank() || amount == "full") u->set_hitpoints(u->max_hitpoints()); @@ -857,9 +861,10 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg) if(cfg["fire_event"].to_bool() && secondary_unit) { secondary_unit = false; + const unit_filter ufilt(cfg.child("secondary_unit"), resources::filter_con); for(unit_map::const_unit_iterator unit = resources::units->begin(); unit != resources::units->end(); ++unit) { - if ( unit_filter::matches_filter(cfg.child("secondary_unit"), *unit, resources::filter_con) ) + if ( ufilt( *unit) ) { killer_loc = entity_location(*unit); secondary_unit = true; @@ -873,8 +878,9 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg) //Find all the dead units first, because firing events ruins unit_map iteration std::vector dead_men_walking; + const unit_filter ufilt(cfg, resources::filter_con); BOOST_FOREACH(unit & u, *resources::units){ - if ( unit_filter::matches_filter(cfg,u, resources::filter_con) ) { + if ( ufilt(u) ) { dead_men_walking.push_back(&u); } } @@ -942,13 +948,14 @@ WML_HANDLER_FUNCTION(kill, event_info, cfg) if((cfg_x.empty() || cfg_x == "recall") && (cfg_y.empty() || cfg_y == "recall")) { + const unit_filter ufilt(cfg, resources::filter_con); //remove the unit from the corresponding team's recall list for(std::vector::iterator pi = resources::teams->begin(); pi!=resources::teams->end(); ++pi) { for(std::vector::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 (unit_filter::matches_filter(cfg, *(*j), map_location(), resources::filter_con)) { + if (ufilt( *(*j), map_location() )) { j = pi->recall_list().erase(j); } else { ++j; @@ -1415,8 +1422,9 @@ WML_HANDLER_FUNCTION(object, event_info, cfg) map_location loc; if(!filter.null()) { + const unit_filter ufilt(filter, resources::filter_con); BOOST_FOREACH(const unit &u, *resources::units) { - if ( unit_filter::matches_filter(filter,u, resources::filter_con) ) { + if ( ufilt(u) ) { loc = u.get_location(); break; } @@ -1431,7 +1439,7 @@ WML_HANDLER_FUNCTION(object, event_info, cfg) std::string command_type = "then"; - if ( u != resources::units->end() && (filter.null() || unit_filter::matches_filter(filter,*u, resources::filter_con)) ) + if ( u != resources::units->end() && (filter.null() || unit_filter(filter, resources::filter_con).matches(*u)) ) { ///@deprecated This can be removed (and a proper duration=level implemented) after 1.11.2 /// Don't forget to remove it from wmllint too! @@ -1527,7 +1535,7 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) */ temp_config["x"] = "recall"; temp_config["y"] = "recall"; - vconfig unit_filter(temp_config); + vconfig unit_filter_cfg(temp_config); const vconfig & leader_filter = cfg.child("secondary_unit"); for(int index = 0; index < int(resources::teams->size()); ++index) { @@ -1543,10 +1551,12 @@ WML_HANDLER_FUNCTION(recall, /*event_info*/, cfg) recall_list_manager & avail = (*resources::teams)[index].recall_list(); std::vector leaders = resources::units->find_leaders(index + 1); + const unit_filter ufilt(unit_filter_cfg, resources::filter_con); + const unit_filter lfilt(leader_filter, resources::filter_con); // Note that if leader_filter is null, this correctly gives a null filter that matches all units. for(std::vector::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 (unit_filter::matches_filter(unit_filter, *(*u), map_location(), resources::filter_con)) { + if (ufilt(*(*u), map_location())) { DBG_NG << (*u)->id() << " matched the filter...\n"; const unit_ptr to_recruit = *u; const unit* pass_check = to_recruit.get(); @@ -1557,8 +1567,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() || unit_filter::matches_filter(leader_filter, *leader, resources::filter_con)) && - unit_filter::matches_filter(vconfig(leader->recall_filter()), *(*u),map_location(), resources::filter_con) ) { + if ( lfilt(*leader) && + unit_filter(vconfig(leader->recall_filter()), resources::filter_con).matches( *(*u),map_location() ) ) { 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(); @@ -1720,13 +1730,13 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg) std::vector::iterator ti = types.begin(), ti_end = types.end(); // loop to give precedence based on type order + const unit_filter ufilt(filter, resources::filter_con); do { if (has_any_types) { item["type"] = *ti; } - unit_map::iterator itor; BOOST_FOREACH(unit &u, *resources::units) { - if ( unit_filter::matches_filter(filter,u, resources::filter_con) ) { + if ( ufilt(u) ) { u.set_role(cfg["role"]); found = true; break; @@ -1746,6 +1756,7 @@ WML_HANDLER_FUNCTION(role, /*event_info*/, cfg) } // loop to give precedence based on type order std::vector::iterator ti = types.begin(); + const unit_filter ufilt(filter, resources::filter_con); do { if (has_any_types) { item["type"] = *ti; @@ -1763,7 +1774,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 (unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)) { + if (ufilt( *u, map_location() )) { u->set_role(cfg["role"]); found=true; break; @@ -2286,8 +2297,9 @@ WML_HANDLER_FUNCTION(teleport, event_info, cfg) // Search for a valid unit filter, and if we have one, look for the matching unit const vconfig & filter = cfg.child("filter"); if(!filter.null()) { + const unit_filter ufilt(filter, resources::filter_con); for (u = resources::units->begin(); u != resources::units->end(); ++u){ - if ( unit_filter::matches_filter(filter,*u, resources::filter_con) ) + if ( ufilt(*u) ) break; } } diff --git a/src/game_events/conditional_wml.cpp b/src/game_events/conditional_wml.cpp index 249b94e34031..fe814e55ebd5 100644 --- a/src/game_events/conditional_wml.cpp +++ b/src/game_events/conditional_wml.cpp @@ -74,9 +74,10 @@ namespace { // Support functions std::vector > counts = (*u).has_attribute("count") ? utils::parse_ranges((*u)["count"]) : default_counts; int match_count = 0; + const unit_filter ufilt(*u, resources::filter_con); BOOST_FOREACH(const unit &i, *resources::units) { - if ( i.hitpoints() > 0 && unit_filter::matches_filter(*u,i, resources::filter_con) ) { + if ( i.hitpoints() > 0 && ufilt(i) ) { ++match_count; if(counts == default_counts) { // by default a single match is enough, so avoid extra work @@ -86,6 +87,7 @@ namespace { // Support functions } if ((*u)["search_recall_list"].to_bool()) { + const unit_filter ufilt(*u, resources::filter_con); for(std::vector::iterator team = resources::teams->begin(); team!=resources::teams->end(); ++team) { @@ -97,7 +99,7 @@ namespace { // Support functions break; } scoped_recall_unit auto_store("this_unit", team->save_id(), t); - if ( unit_filter::matches_filter(*u,*team->recall_list()[t], resources::filter_con) ) { + if ( ufilt( *team->recall_list()[t] ) ) { ++match_count; } } diff --git a/src/game_events/entity_location.cpp b/src/game_events/entity_location.cpp index 310b3c3f2bbf..1d8bfb80c8ff 100644 --- a/src/game_events/entity_location.cpp +++ b/src/game_events/entity_location.cpp @@ -20,7 +20,6 @@ #include "global.hpp" #include "entity_location.hpp" -#include "../game_board.hpp" #include "../resources.hpp" #include "../unit.hpp" #include "../unit_filter.hpp" @@ -101,7 +100,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 unit_filter::matches_filter(filter, *un_it, filter_loc_, resources::filter_con) && + return unit_filter(filter, resources::filter_con).matches(*un_it, filter_loc_) && matches_unit(un_it); } diff --git a/src/pathfind/teleport.cpp b/src/pathfind/teleport.cpp index aef34495cd1b..dda736148143 100644 --- a/src/pathfind/teleport.cpp +++ b/src/pathfind/teleport.cpp @@ -76,7 +76,8 @@ 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 (unit_filter::matches_filter(filter, u, loc, resources::filter_con)) { + const unit_filter ufilt(filter, resources::filter_con); + if (ufilt.matches(u, loc)) { scoped_xy_unit teleport_unit("teleport_unit", loc.x, loc.y, *resources::units); diff --git a/src/scripting/lua.cpp b/src/scripting/lua.cpp index 4cfb15b7dde9..e3e68371fbb8 100644 --- a/src/scripting/lua.cpp +++ b/src/scripting/lua.cpp @@ -856,10 +856,11 @@ static int intf_get_units(lua_State *L) lua_newtable(L); int i = 1; unit_map &units = *resources::units; + const unit_filter ufilt(filter, resources::filter_con); // note that if filter is null, this yields a null filter matching everything for (unit_map::const_unit_iterator ui = units.begin(), ui_end = units.end(); ui != ui_end; ++ui) { - if (!filter.null() && !unit_filter::matches_filter(filter, *ui, ui->get_location(), resources::filter_con)) + if (!ufilt(*ui)) continue; new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(ui->underlying_id()); lua_pushvalue(L, 1); @@ -896,11 +897,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, unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)); + lua_pushboolean(L, unit_filter(filter, resources::filter_con).matches(*u, map_location())); return 1; } - lua_pushboolean(L, unit_filter::matches_filter(filter, *u, u->get_location(), resources::filter_con)); + lua_pushboolean(L, unit_filter(filter, resources::filter_con).matches(*u)); return 1; } @@ -922,6 +923,7 @@ static int intf_get_recall_units(lua_State *L) lua_rawget(L, LUA_REGISTRYINDEX); lua_newtable(L); int i = 1, s = 1; + const unit_filter ufilt(filter, resources::filter_con); BOOST_FOREACH(team &t, *resources::teams) { BOOST_FOREACH(unit_ptr & u, t.recall_list()) @@ -929,7 +931,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 (!unit_filter::matches_filter(filter, *u, map_location(), resources::filter_con)) + if (!ufilt( *u, map_location() )) continue; } new(lua_newuserdata(L, sizeof(lua_unit))) lua_unit(s, u->underlying_id()); @@ -2000,11 +2002,12 @@ static int intf_find_cost_map(lua_State *L) else if (!filter.null()) // 1. arg - filter { unit_map &units = *resources::units; + const unit_filter ufilt(filter, resources::filter_con); for (unit_map::const_unit_iterator ui = units.begin(), ui_end = units.end(); ui != ui_end; ++ui) { bool on_map = ui->get_location().valid(); - if (on_map && unit_filter::matches_filter(filter, *ui,ui->get_location(), resources::filter_con)) + if (on_map && ufilt(*ui)) { real_units. push_back(&(*ui)); } diff --git a/src/side_filter.cpp b/src/side_filter.cpp index a40acbd491aa..75074275e121 100644 --- a/src/side_filter.cpp +++ b/src/side_filter.cpp @@ -135,21 +135,22 @@ bool side_filter::match_internal(const team &t) const //Allow filtering on units if(cfg_.has_child("has_unit")) { - const vconfig& unit_filter = cfg_.child("has_unit"); + const vconfig & ufilt_cfg = cfg_.child("has_unit"); + const unit_filter ufilt(ufilt_cfg, fc_, flat_); bool found = false; BOOST_FOREACH(const unit &u, fc_->get_disp_context().units()) { if (u.side() != t.side()) { continue; } - if (unit_filter::matches_filter(unit_filter, u, u.get_location(), fc_, flat_)) { + if (ufilt(u)) { found = true; break; } } - if(!found && unit_filter["search_recall_list"].to_bool(false)) { + if(!found && ufilt_cfg["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(unit_filter::matches_filter(unit_filter, *u, u->get_location(), fc_, flat_)) { + if(ufilt(*u)) { found = true; break; } diff --git a/src/terrain_filter.cpp b/src/terrain_filter.cpp index 3a429425ff89..1958f619dcd3 100644 --- a/src/terrain_filter.cpp +++ b/src/terrain_filter.cpp @@ -153,9 +153,9 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x //Allow filtering on unit if(cfg_.has_child("filter")) { - const vconfig& unit_filter = cfg_.child("filter"); + const unit_filter ufilt(vconfig(cfg_.child("filter")), fc_, flat_); const unit_map::const_iterator u = fc_->get_disp_context().units().find(loc); - if (u == fc_->get_disp_context().units().end() || !unit_filter::matches_filter(unit_filter, *u, loc, fc_, flat_)) + if (u == fc_->get_disp_context().units().end() || !ufilt( *u, loc)) return false; } diff --git a/src/unit.cpp b/src/unit.cpp index 444d4a7ad8f1..1cb630cfa4d8 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -1580,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 (!unit_filter::matches_filter(vconfig(afilter), *this, loc_, resources::filter_con)) continue; + if (!unit_filter(vconfig(afilter), resources::filter_con).matches(*this, loc_)) continue; const std::string &apply_to = effect["apply_to"]; const std::string &apply_times = effect["times"]; diff --git a/src/unit_abilities.cpp b/src/unit_abilities.cpp index 7a02686f3104..354cdb6a9d56 100644 --- a/src/unit_abilities.cpp +++ b/src/unit_abilities.cpp @@ -297,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 ( !unit_filter::matches_filter(vconfig(afilter), *this, loc, resources::filter_con, illuminates) ) + if ( !unit_filter(vconfig(afilter), resources::filter_con, illuminates).matches(*this, loc) ) return false; map_location adjacent[6]; @@ -306,6 +306,7 @@ bool unit::ability_active(const std::string& ability,const config& cfg,const map BOOST_FOREACH(const config &i, cfg.child_range("filter_adjacent")) { + const unit_filter ufilt(vconfig(i), resources::filter_con, illuminates); BOOST_FOREACH(const std::string &j, utils::split(i["adjacent"])) { map_location::DIRECTION index = @@ -315,21 +316,22 @@ 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_filter::matches_filter(vconfig(i), *unit, unit->get_location(), resources::filter_con, illuminates)) + if (!ufilt( *unit )) return false; } } BOOST_FOREACH(const config &i, cfg.child_range("filter_adjacent_location")) { + terrain_filter adj_filter(vconfig(i), resources::filter_con); + adj_filter.flatten(illuminates); + BOOST_FOREACH(const std::string &j, utils::split(i["adjacent"])) { map_location::DIRECTION index = map_location::parse_direction(j); if (index == map_location::NDIRECTIONS) { continue; } - terrain_filter adj_filter(vconfig(i), resources::filter_con); - adj_filter.flatten(illuminates); if(!adj_filter.match(adjacent[index])) { return false; } @@ -348,12 +350,13 @@ bool unit::ability_affects_adjacent(const std::string& ability, const config& cf assert(dir >=0 && dir <= 5); static const std::string adjacent_names[6] = {"n","ne","se","s","sw","nw"}; + BOOST_FOREACH(const config &i, cfg.child_range("affect_adjacent")) { std::vector 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 ( unit_filter::matches_filter(vconfig(filter), *this, loc, resources::filter_con, illuminates) ) + if ( unit_filter(vconfig(filter), resources::filter_con, illuminates).matches(*this, loc) ) return true; } else return true; @@ -371,7 +374,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 unit_filter::matches_filter(vconfig(filter), *this, loc, resources::filter_con, ability == "illuminates"); + return unit_filter(vconfig(filter), resources::filter_con, ability == "illuminates").matches(*this, loc); } bool unit::has_ability_type(const std::string& ability) const @@ -794,7 +797,7 @@ namespace { // Helpers for attack_type::special_active() return true; // Check for a unit match. - if ( !un_it.valid() || !unit_filter::matches_filter(vconfig(filter_child), *un_it, loc, resources::filter_con) ) + if ( !un_it.valid() || !unit_filter(vconfig(filter_child), resources::filter_con).matches(*un_it, loc) ) return false; // Check for a weapon match. @@ -884,7 +887,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_filter::matches_filter(vconfig(i), *unit, adjacent[index], resources::filter_con) ) + !unit_filter(vconfig(i), resources::filter_con).matches(*unit, adjacent[index]) ) //TODO: Should this filter get precomputed? return false; } } diff --git a/src/unit_animation.cpp b/src/unit_animation.cpp index 1ccb0a93116b..9e6df5b17c20 100644 --- a/src/unit_animation.cpp +++ b/src/unit_animation.cpp @@ -404,7 +404,7 @@ int unit_animation::matches(const display &disp, const map_location& loc,const m } std::vector::const_iterator myitor; for(myitor = unit_filter_.begin(); myitor != unit_filter_.end(); ++myitor) { - if (!unit_filter::matches_filter(vconfig(*myitor), *my_unit, loc, &disp)) return MATCH_FAIL; + if (!unit_filter(vconfig(*myitor), &disp).matches(*my_unit, loc)) return MATCH_FAIL; //TODO: Precalculate these ++result; } if(!secondary_unit_filter_.empty()) { @@ -413,7 +413,7 @@ int unit_animation::matches(const display &disp, const map_location& loc,const m if (unit->get_location() == second_loc) { std::vector::const_iterator second_itor; for(second_itor = secondary_unit_filter_.begin(); second_itor != secondary_unit_filter_.end(); ++second_itor) { - if (!unit_filter::matches_filter(vconfig(*second_itor), *unit, second_loc, &disp)) return MATCH_FAIL; + if (!unit_filter(vconfig(*second_itor), &disp).matches(*unit, second_loc)) return MATCH_FAIL; //TODO: Precalculate these result++; } diff --git a/src/unit_display.cpp b/src/unit_display.cpp index 1a46437d3a5b..73b3d3fccf06 100644 --- a/src/unit_display.cpp +++ b/src/unit_display.cpp @@ -773,8 +773,9 @@ void wml_animation_internal(unit_animator &animator, const vconfig &cfg, const m // and if we have one, look for the matching unit vconfig filter = cfg.child("filter"); if(!filter.null()) { + const unit_filter ufilt(filter, resources::filter_con); for (u = resources::units->begin(); u != resources::units->end(); ++u) { - if ( unit_filter::matches_filter(filter, *u, resources::filter_con) ) + if ( ufilt(*u) ) break; } } diff --git a/src/unit_filter.cpp b/src/unit_filter.cpp index 492c4f105e97..387ea83e429c 100644 --- a/src/unit_filter.cpp +++ b/src/unit_filter.cpp @@ -32,29 +32,70 @@ #include -namespace { bool internal_matches_filter(const vconfig& filter, const unit & u, const map_location& loc, const filter_context * fc, bool use_flat_tod); } +bool unit_filter::matches(const unit & u) const { + return matches (u, u.get_location()); +} + +//bool unit_filter::matches(const unit & /*u*/, const map_location & /*loc*/) const { +// assert(false && "called match against a pure abstract unit_filter! this indicates a programmer error, this function must be overrided"); +// return false; +//} + +class null_unit_filter_impl : public unit_filter_abstract_impl { +public: + null_unit_filter_impl() {} + virtual bool matches(const unit & /*u*/, const map_location & /*loc*/) const { + return true; + } + + ~null_unit_filter_impl() {} +}; + +class basic_unit_filter_impl : public unit_filter_abstract_impl { +public: + basic_unit_filter_impl(const vconfig & vcfg, const filter_context & fc, bool flat_tod) + : vcfg_(vcfg) + , fc_(fc) + , use_flat_tod_(flat_tod) + {} + virtual bool matches(const unit & u, const map_location & loc) const; + + ~basic_unit_filter_impl() {} +private: + const vconfig & vcfg_; + const filter_context & fc_; + bool use_flat_tod_; -namespace unit_filter { + bool internal_matches_filter(const unit & u, const map_location & loc) const; +}; -bool matches_filter(const vconfig& filter, const unit & u, const filter_context * fc, bool use_flat_tod) -{ return matches_filter(filter, u, u.get_location(), fc, use_flat_tod); } +unit_filter::unit_filter(const vconfig & vcfg, const filter_context * fc, bool flat_tod) +{ + if (!fc) { + assert(false && "attempt to instantiate a unit filter with a null filter context!"); + } + if (vcfg.null()) { + impl_.reset(new null_unit_filter_impl()); + } + impl_.reset(new basic_unit_filter_impl(vcfg, *fc, flat_tod)); + //TODO: Add more efficient implementations for special cases +} -bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, const filter_context * fc, bool use_flat_tod) +bool basic_unit_filter_impl::matches(const unit & u, const map_location& loc) const { bool matches = true; if(loc.valid()) { - assert(fc != NULL); - scoped_xy_unit auto_store("this_unit", loc.x, loc.y, fc->get_disp_context().units()); - matches = internal_matches_filter(cfg, u, loc, fc, use_flat_tod); + scoped_xy_unit auto_store("this_unit", loc.x, loc.y, fc_.get_disp_context().units()); + matches = internal_matches_filter(u, loc); } else { // If loc is invalid, then this is a recall list unit (already been scoped) - matches = internal_matches_filter(cfg, u, loc, fc, use_flat_tod); + matches = internal_matches_filter(u, loc); } // 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(); + vconfig::all_children_iterator cond = vcfg_.ordered_begin(); + vconfig::all_children_iterator cond_end = vcfg_.ordered_end(); while(cond != cond_end) { @@ -63,15 +104,15 @@ bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, // Handle [and] if(cond_name == "and") { - matches = matches && matches_filter(cond_filter,u, loc, fc, use_flat_tod); + matches = matches && unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); } // Handle [or] else if(cond_name == "or") { - matches = matches || matches_filter(cond_filter,u, loc, fc,use_flat_tod); + matches = matches || unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); } // Handle [not] else if(cond_name == "not") { - matches = matches && !matches_filter(cond_filter,u, loc, fc,use_flat_tod); + matches = matches && !unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); } ++cond; @@ -79,18 +120,14 @@ bool matches_filter(const vconfig& cfg, const unit & u, const map_location& loc, 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 filter_context * fc, bool use_flat_tod) +bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_location& loc) const { - config::attribute_value cfg_name = cfg["name"]; + config::attribute_value cfg_name = vcfg_["name"]; if (!cfg_name.blank() && cfg_name.str() != u.name()) { return false; } - const config::attribute_value cfg_id = cfg["id"]; + const config::attribute_value cfg_id = vcfg_["id"]; if (!cfg_id.blank()) { const std::string& id = cfg_id; const std::string& this_id = u.id(); @@ -109,35 +146,33 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // Allow 'speaker' as an alternative to id, since people use it so often - config::attribute_value cfg_speaker = cfg["speaker"]; + config::attribute_value cfg_speaker = vcfg_["speaker"]; if (!cfg_speaker.blank() && cfg_speaker.str() != u.id()) { return false; } - if(cfg.has_child("filter_location")) { - assert(fc != NULL); - const vconfig& t_cfg = cfg.child("filter_location"); - terrain_filter t_filter(t_cfg, fc, use_flat_tod); + if(vcfg_.has_child("filter_location")) { + const vconfig& t_cfg = vcfg_.child("filter_location"); + terrain_filter t_filter(t_cfg, &fc_, use_flat_tod_); if(!t_filter.match(loc)) { return false; } } - const vconfig& filter_side = cfg.child("filter_side"); + const vconfig& filter_side = vcfg_.child("filter_side"); if(!filter_side.null()) { - side_filter s_filter(filter_side, fc); + side_filter s_filter(filter_side, &fc_); 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"]; + config::attribute_value cfg_x = vcfg_["x"]; + config::attribute_value cfg_y = vcfg_["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 ((!fc && loc.valid()) || - (fc && fc->get_disp_context().map().on_board(loc))) + if (fc_.get_disp_context().map().on_board(loc)) { return false; } @@ -149,7 +184,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // The type could be a comma separated list of types - config::attribute_value cfg_type = cfg["type"]; + config::attribute_value cfg_type = vcfg_["type"]; if (!cfg_type.blank()) { const std::string type_ids = cfg_type.str(); @@ -173,7 +208,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // The variation_type could be a comma separated list of types - config::attribute_value cfg_variation_type = cfg["variation"]; + config::attribute_value cfg_variation_type = vcfg_["variation"]; if (!cfg_variation_type.blank()) { const std::string type_ids = cfg_variation_type.str(); @@ -197,7 +232,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } // The has_variation_type could be a comma separated list of types - config::attribute_value cfg_has_variation_type = cfg["has_variation"]; + config::attribute_value cfg_has_variation_type = vcfg_["has_variation"]; if (!cfg_has_variation_type.blank()) { const std::string& var_ids = cfg_has_variation_type.str(); @@ -223,7 +258,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_ability = cfg["ability"]; + config::attribute_value cfg_ability = vcfg_["ability"]; if (!cfg_ability.blank()) { std::string ability = cfg_ability; @@ -246,7 +281,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_race = cfg["race"]; + config::attribute_value cfg_race = vcfg_["race"]; if (!cfg_race.blank()) { std::string race = cfg_race; @@ -258,12 +293,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_gender = cfg["gender"]; + config::attribute_value cfg_gender = vcfg_["gender"]; if (!cfg_gender.blank() && string_gender(cfg_gender) != u.gender()) { return false; } - config::attribute_value cfg_side = cfg["side"]; + config::attribute_value cfg_side = vcfg_["side"]; if (!cfg_side.blank() && cfg_side.to_int() != u.side()) { std::string side = cfg_side; if ( side.find(',') == std::string::npos ) { @@ -275,7 +310,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_has_weapon = cfg["has_weapon"]; + config::attribute_value cfg_has_weapon = vcfg_["has_weapon"]; if (!cfg_has_weapon.blank()) { std::string weapon = cfg_has_weapon; bool has_weapon = false; @@ -292,38 +327,38 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_role = cfg["role"]; + config::attribute_value cfg_role = vcfg_["role"]; if (!cfg_role.blank() && cfg_role.str() != u.get_role()) { return false; } - config::attribute_value cfg_ai_special = cfg["ai_special"]; + config::attribute_value cfg_ai_special = vcfg_["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"]; + config::attribute_value cfg_canrecruit = vcfg_["canrecruit"]; if (!cfg_canrecruit.blank() && cfg_canrecruit.to_bool() != u.can_recruit()) { return false; } - config::attribute_value cfg_recall_cost = cfg["recall_cost"]; + config::attribute_value cfg_recall_cost = vcfg_["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"]; + config::attribute_value cfg_level = vcfg_["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(fc->get_disp_context().map().get_terrain(loc))) { + config::attribute_value cfg_defense = vcfg_["defense"]; + if (!cfg_defense.blank() && cfg_defense.to_int(-1) != u.defense_modifier(fc_.get_disp_context().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(fc->get_disp_context().map().get_terrain(loc))) { + config::attribute_value cfg_movement = vcfg_["movement_cost"]; + if (!cfg_movement.blank() && cfg_movement.to_int(-1) != u.movement_cost(fc_.get_disp_context().map().get_terrain(loc))) { return false; } @@ -331,7 +366,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat // 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"); + const vconfig::child_list& wmlcfgs = vcfg_.get_children("filter_wml"); if (!wmlcfgs.empty()) { config unit_cfg; for (unsigned i = 0; i < wmlcfgs.size(); ++i) @@ -355,14 +390,14 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - if (cfg.has_child("filter_vision")) { - const vconfig::child_list& vis_filt = cfg.get_children("filter_vision"); + if (vcfg_.has_child("filter_vision")) { + const vconfig::child_list& vis_filt = vcfg_.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 viewers; // Use standard side filter - side_filter ssf(*i, fc); + side_filter ssf(*i, &fc_); std::vector sides = ssf.get_teams(); viewers.insert(sides.begin(), sides.end()); if (viewers.empty()) { @@ -370,7 +405,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } std::set::const_iterator viewer, viewer_end = viewers.end(); for (viewer = viewers.begin(); viewer != viewer_end; ++viewer) { - bool fogged = fc->get_disp_context().teams()[*viewer - 1].fogged(loc); + bool fogged = fc_.get_disp_context().teams()[*viewer - 1].fogged(loc); bool hiding = u.invisible(loc/*, false(?) */); bool unit_hidden = fogged || hiding; if (visible == unit_hidden) return false; @@ -378,13 +413,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - if (cfg.has_child("filter_adjacent")) { - assert(fc); - const unit_map& units = fc->get_disp_context().units(); + if (vcfg_.has_child("filter_adjacent")) { + const unit_map& units = fc_.get_disp_context().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"); + const vconfig::child_list& adj_filt = vcfg_.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"]; @@ -394,12 +428,12 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat 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(), fc, use_flat_tod)) { + || !unit_filter(*i, &fc_, use_flat_tod_).matches(*unit_itor)) { continue; } config::attribute_value i_is_enemy = (*i)["is_enemy"]; if (i_is_enemy.blank() || i_is_enemy.to_bool() == - fc->get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) { + fc_.get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) { ++match_count; } } @@ -413,7 +447,7 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat } } - config::attribute_value cfg_find_in = cfg["find_in"]; + config::attribute_value cfg_find_in = vcfg_["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); @@ -429,14 +463,14 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat return false; } } - config::attribute_value cfg_formula = cfg["formula"]; + config::attribute_value cfg_formula = vcfg_["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"]; + config::attribute_value cfg_lua_function = vcfg_["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; @@ -444,5 +478,3 @@ bool internal_matches_filter(const vconfig& cfg, const unit & u, const map_locat return true; } - -} //end anonymous namespace diff --git a/src/unit_filter.hpp b/src/unit_filter.hpp index 1d8d8b757173..06c9e3d82417 100644 --- a/src/unit_filter.hpp +++ b/src/unit_filter.hpp @@ -23,17 +23,37 @@ * these to speed up repeated application of the filter. */ +#include + class filter_context; class unit; class vconfig; struct map_location; -namespace unit_filter { +class unit_filter_abstract_impl { +public: + virtual bool matches(const unit & u, const map_location & loc) const = 0; +}; + +class unit_filter { +public: + unit_filter(const vconfig & cfg, const filter_context * fc, bool use_flat_tod = false); //!< Constructs a unit filter from a config and a context. This function should give the most efficient implementation available. - bool matches_filter(const vconfig& cfg,const unit & u, const map_location& loc, const filter_context * board, bool use_flat_tod=false); + bool matches(const unit & u, const map_location & loc) const { + return impl_->matches(u,loc); + } /// 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 filter_context* board, bool use_flat_tod=false); + bool matches(const unit & u) const; + + bool operator()(const unit & u, const map_location & loc) const { + return matches(u,loc); + } -} + bool operator()(const unit & u) const { + return matches(u); + } +private: + boost::scoped_ptr impl_; +}; From f40b446f8727b37a9aee75b0b3ad60ad4eae2453 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 3 Jul 2014 16:06:56 -0400 Subject: [PATCH 7/7] preprocess conditional children of unit filters --- src/unit_filter.cpp | 81 ++++++++++++++++++++++++++++++++------------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/src/unit_filter.cpp b/src/unit_filter.cpp index 387ea83e429c..4593c1d4f664 100644 --- a/src/unit_filter.cpp +++ b/src/unit_filter.cpp @@ -18,6 +18,7 @@ #include "config.hpp" #include "display_context.hpp" #include "filter_context.hpp" +#include "make_enum.hpp" #include "map_location.hpp" #include "resources.hpp" //Needed for lua kernel pointer #include "scripting/lua.hpp" //Needed for lua kernel @@ -31,7 +32,10 @@ #include "variable.hpp" // needed for vconfig, scoped unit #include +#include +#include +///Defined out of line to prevent including unit at unit_filter.hpp bool unit_filter::matches(const unit & u) const { return matches (u, u.get_location()); } @@ -41,6 +45,7 @@ bool unit_filter::matches(const unit & u) const { // return false; //} +/// Null unit filter is built when the input config is null class null_unit_filter_impl : public unit_filter_abstract_impl { public: null_unit_filter_impl() {} @@ -51,24 +56,62 @@ class null_unit_filter_impl : public unit_filter_abstract_impl { ~null_unit_filter_impl() {} }; +/// This enum helps to evaluate conditional filters +namespace conditional { + MAKE_ENUM (TYPE, + (AND, "and") + (OR, "or") + (NOT, "not") + ) + MAKE_ENUM_STREAM_OPS1(TYPE) + + static TYPE warning_suppressor = string_to_TYPE_default("foo", NOT); +} + +/// The basic unit filter gives a generic implementation of the match fcn class basic_unit_filter_impl : public unit_filter_abstract_impl { public: basic_unit_filter_impl(const vconfig & vcfg, const filter_context & fc, bool flat_tod) : vcfg_(vcfg) , fc_(fc) , use_flat_tod_(flat_tod) - {} + { + // Handle [and], [or], and [not] with in-order precedence + vconfig::all_children_iterator cond = vcfg_.ordered_begin(); + vconfig::all_children_iterator cond_end = vcfg_.ordered_end(); + while(cond != cond_end) + { + try { + const std::string& cond_name = cond.get_key(); + conditional::TYPE type = conditional::string_to_TYPE(cond_name); // throws bad_enum_cast if we don't get a string match with any enum + + const vconfig& cond_filter = cond.get_child(); + + cond_children_.push_back(new basic_unit_filter_impl(cond_filter, fc_, use_flat_tod_)); + cond_child_types_.push_back(type); + } catch (bad_enum_cast &) {} //ignore tags that aren't conditionals + + ++cond; + } + } + virtual bool matches(const unit & u, const map_location & loc) const; ~basic_unit_filter_impl() {} private: - const vconfig & vcfg_; + const vconfig vcfg_; const filter_context & fc_; bool use_flat_tod_; + boost::ptr_vector cond_children_; + std::vector cond_child_types_; + bool internal_matches_filter(const unit & u, const map_location & loc) const; }; +/** Ctor of unit filter + * unit_filter::unit_filter acts as a factory, selecting the appropriate implementation class + */ unit_filter::unit_filter(const vconfig & vcfg, const filter_context * fc, bool flat_tod) { if (!fc) { @@ -81,6 +124,9 @@ unit_filter::unit_filter(const vconfig & vcfg, const filter_context * fc, bool f //TODO: Add more efficient implementations for special cases } +/** Begin implementations of filter impl's + */ + bool basic_unit_filter_impl::matches(const unit & u, const map_location& loc) const { bool matches = true; @@ -94,28 +140,17 @@ bool basic_unit_filter_impl::matches(const unit & u, const map_location& loc) co } // Handle [and], [or], and [not] with in-order precedence - vconfig::all_children_iterator cond = vcfg_.ordered_begin(); - vconfig::all_children_iterator cond_end = vcfg_.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 && unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); - } - // Handle [or] - else if(cond_name == "or") { - matches = matches || unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); - } - // Handle [not] - else if(cond_name == "not") { - matches = matches && !unit_filter(cond_filter, &fc_, use_flat_tod_).matches(u, loc); + for (size_t i = 0; i < cond_children_.size(); i++) { + switch (cond_child_types_[i]) { + case conditional::AND: + matches = matches && cond_children_[i].matches(u,loc); + break; + case conditional::OR: + matches = matches || cond_children_[i].matches(u,loc); + break; + case conditional::NOT: + matches = matches && !cond_children_[i].matches(u,loc); } - - ++cond; } return matches; }