now radius expansion is handled last in Standard Location Filters;
previously it was handled last except before [and], [or], and [not] note: this allows more advanced uses of the radius expansion feature
This commit is contained in:
parent
dfed4536de
commit
a7b7e35add
7 changed files with 147 additions and 131 deletions
|
@ -21,6 +21,8 @@ Version 1.3.7+svn:
|
|||
* remove the unused [neighbour_unit_filter] animation filter, now that SUF
|
||||
does it for us (and better)
|
||||
* a minus sign in front of a cardinal direction now reverses it ("-s"="n")
|
||||
* now radius expansion is handled last in Standard Location Filters;
|
||||
previously it was handled last except before [and], [or], and [not]
|
||||
* graphics:
|
||||
* new graphics for the highwayman
|
||||
* no more idle animations for units next to an enemy unit
|
||||
|
|
|
@ -456,11 +456,11 @@ Soooo... It is you who sent your subordinates to attack us. Now when we've destr
|
|||
[event]
|
||||
name=start
|
||||
[store_locations]
|
||||
x=14
|
||||
y=9
|
||||
radius=10
|
||||
terrain=*^V*
|
||||
[and]
|
||||
terrain=*^V*
|
||||
x=14
|
||||
y=9
|
||||
radius=10
|
||||
[/and]
|
||||
variable=temp_starting_villages_area
|
||||
[/store_locations]
|
||||
|
@ -478,11 +478,11 @@ Soooo... It is you who sent your subordinates to attack us. Now when we've destr
|
|||
[event]
|
||||
name=start
|
||||
[store_locations]
|
||||
x=34
|
||||
y=7
|
||||
radius=10
|
||||
terrain=*^V*
|
||||
[and]
|
||||
terrain=*^V*
|
||||
x=34
|
||||
y=7
|
||||
radius=10
|
||||
[/and]
|
||||
variable=temp_starting_villages_area
|
||||
[/store_locations]
|
||||
|
|
|
@ -548,14 +548,13 @@ _f, _f, _f, _f, _f, _f, Re, _f, _f, _f, _f, _f,
|
|||
[store_locations]
|
||||
variable=potential_locs
|
||||
terrain=Xu
|
||||
[and]
|
||||
terrain=U*
|
||||
radius=1
|
||||
[/and]
|
||||
[and]
|
||||
terrain=Re
|
||||
radius=1
|
||||
[/and]
|
||||
[filter_adjacent_location]
|
||||
terrain=U*, Re
|
||||
[filter_adjacent_location]
|
||||
terrain=U*, Re
|
||||
count=4-5
|
||||
[/filter_adjacent_location]
|
||||
[/filter_adjacent_location]
|
||||
[not]
|
||||
# don't start near the cave floor around the scepter
|
||||
x=$scepter_x
|
||||
|
|
|
@ -304,10 +304,10 @@
|
|||
[/store_unit]
|
||||
|
||||
[store_locations]
|
||||
x,y=$ethiliel_loc.x,$ethiliel_loc.y
|
||||
radius=3
|
||||
terrain=Gs^Fp
|
||||
[and]
|
||||
terrain=Gs^Fp
|
||||
x,y=$ethiliel_loc.x,$ethiliel_loc.y
|
||||
radius=3
|
||||
[/and]
|
||||
variable=bodyguard_loc
|
||||
[/store_locations]
|
||||
|
|
|
@ -3691,12 +3691,11 @@
|
|||
# there, if the hex is empty teleport Kaleh there
|
||||
|
||||
[store_locations]
|
||||
x={X_LOC}
|
||||
y={Y_LOC}
|
||||
radius=1
|
||||
[and]
|
||||
terrain=Uu, Re, Uu^Vu, Cud, Ke, Uh, Uu^Uf
|
||||
[/and]
|
||||
[filter_adjacent_location]
|
||||
x={X_LOC}
|
||||
y={Y_LOC}
|
||||
[/filter_adjacent_location]
|
||||
terrain=Uu, Re, Uu^Vu, Cud, Ke, Uh, Uu^Uf
|
||||
[not]
|
||||
[filter]
|
||||
[/filter]
|
||||
|
@ -5671,12 +5670,11 @@
|
|||
# find adjacent hex with cave floor or dirt
|
||||
|
||||
[store_locations]
|
||||
x=$coord_x
|
||||
y=$coord_y
|
||||
radius=1
|
||||
[and]
|
||||
terrain=Uu, Re, Uu^Vu, Ce, Ke, Ch, Rr, Qxu, Uh, Uu^Uf, Ryd
|
||||
[/and]
|
||||
[filter_adjacent_location]
|
||||
x=$coord_x
|
||||
y=$coord_y
|
||||
[/filter_adjacent_location]
|
||||
terrain=Uu, Re, Uu^Vu, Ce, Ke, Ch, Rr, Qxu, Uh, Uu^Uf, Ryd
|
||||
variable=hex_loc
|
||||
[/store_locations]
|
||||
|
||||
|
|
|
@ -384,11 +384,11 @@
|
|||
variable=temp_starting_location
|
||||
[/store_starting_location]
|
||||
[store_locations]
|
||||
x,y=$temp_starting_location.x,$temp_starting_location.y
|
||||
radius={RADIUS}
|
||||
#all the types of villages
|
||||
terrain=Ha^Vhha, Hh^Vhh, Dd^Vda, Mm^Vhh, Uu^Vu, Aa^Vea, Gs^Vht, Uu^Vud, Gg^Ve, Dd^Vdt, Gg^Vh, Aa^Vha, Ww^Vm, Ss^Vhs, Ss^Vm
|
||||
[and]
|
||||
terrain=Ha^Vhha, Hh^Vhh, Dd^Vda, Mm^Vhh, Uu^Vu, Aa^Vea, Gs^Vht, Uu^Vud, Gg^Ve, Dd^Vdt, Gg^Vh, Aa^Vha, Ww^Vm, Ss^Vhs, Ss^Vm
|
||||
x,y=$temp_starting_location.x,$temp_starting_location.y
|
||||
radius={RADIUS}
|
||||
[/and]
|
||||
variable=temp_starting_locs
|
||||
[/store_locations]
|
||||
|
@ -416,10 +416,10 @@
|
|||
name=prestart
|
||||
|
||||
[store_locations]
|
||||
x,y={X},{Y}
|
||||
radius={RADIUS}
|
||||
terrain=*^V*
|
||||
[and]
|
||||
terrain=*^V*
|
||||
x,y={X},{Y}
|
||||
radius={RADIUS}
|
||||
[/and]
|
||||
variable=temp_starting_villages_area
|
||||
[/store_locations]
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#define ERR_CF LOG_STREAM(err, config)
|
||||
#define LOG_G LOG_STREAM(info, general)
|
||||
#define ERR_NG LOG_STREAM(err, engine)
|
||||
|
||||
namespace {
|
||||
struct terrain_filter_cache {
|
||||
|
@ -247,76 +248,87 @@ bool terrain_matches_filter(const gamemap& map, const gamemap::location& loc, co
|
|||
const gamestatus& game_status, const unit_map& units, const bool flat_tod,
|
||||
const size_t max_loop)
|
||||
{
|
||||
bool matches = false;
|
||||
if(map.on_board(loc)) {
|
||||
//handle radius
|
||||
const size_t radius = minimum<size_t>(max_loop,
|
||||
lexical_cast_default<size_t>(cfg["radius"], 0));
|
||||
std::set<gamemap::location> hexes;
|
||||
std::vector<gamemap::location> loc_vec(1, loc);
|
||||
if(cfg.has_child("filter_radius")) {
|
||||
terrain_pred tp(map, cfg.child("filter_radius"), game_status, units, flat_tod);
|
||||
get_tiles_radius(map, loc_vec, radius, hexes, &tp);
|
||||
} else {
|
||||
get_tiles_radius(map, loc_vec, radius, hexes);
|
||||
}
|
||||
if(cfg["x"] == "recall" && cfg["y"] == "recall") {
|
||||
return !map.on_board(loc);
|
||||
}
|
||||
std::set<gamemap::location> hexes;
|
||||
std::vector<gamemap::location> loc_vec(1, loc);
|
||||
|
||||
size_t loop_count = 0;
|
||||
std::set<gamemap::location>::const_iterator i;
|
||||
terrain_filter_cache tfc;
|
||||
for(i = hexes.begin(); i != hexes.end() && loop_count <= max_loop && !matches; ++i) {
|
||||
matches = terrain_matches_internal(map, *i, cfg, game_status, units, flat_tod, false, tfc);
|
||||
++loop_count;
|
||||
}
|
||||
} else if(cfg["x"] == "recall" && cfg["y"] == "recall"
|
||||
&& cfg.get_config().values.size() == 2 && cfg.get_config().all_children().empty()) {
|
||||
//locations not on the map are considered to be on a recall list
|
||||
matches = true;
|
||||
//handle radius
|
||||
size_t radius = lexical_cast_default<size_t>(cfg["radius"], 0);
|
||||
if(radius > max_loop) {
|
||||
ERR_NG << "terrain_matches_filter: radius greater than " << max_loop
|
||||
<< ", restricting\n";
|
||||
radius = max_loop;
|
||||
}
|
||||
if(cfg.has_child("filter_radius")) {
|
||||
terrain_pred tp(map, cfg.child("filter_radius"), game_status, units, flat_tod);
|
||||
get_tiles_radius(map, loc_vec, radius, hexes, &tp);
|
||||
} else {
|
||||
get_tiles_radius(map, loc_vec, radius, hexes);
|
||||
}
|
||||
|
||||
//handle [and], [or], and [not] with in-order precedence
|
||||
config::all_children_iterator cond = cfg.get_config().ordered_begin();
|
||||
config::all_children_iterator cond_end = cfg.get_config().ordered_end();
|
||||
while(cond != cond_end)
|
||||
{
|
||||
const std::string& cond_name = *((*cond).first);
|
||||
const vconfig cond_filter(&(*((*cond).second)));
|
||||
size_t loop_count = 0;
|
||||
std::set<gamemap::location>::const_iterator i;
|
||||
terrain_filter_cache tfc;
|
||||
for(i = hexes.begin(); i != hexes.end(); ++i) {
|
||||
bool matches = terrain_matches_internal(map, *i, cfg, game_status, units, flat_tod, false, tfc);
|
||||
|
||||
//handle [and]
|
||||
if(cond_name == "and")
|
||||
//handle [and], [or], and [not] with in-order precedence
|
||||
config::all_children_iterator cond = cfg.get_config().ordered_begin();
|
||||
config::all_children_iterator cond_end = cfg.get_config().ordered_end();
|
||||
while(cond != cond_end)
|
||||
{
|
||||
matches = matches &&
|
||||
terrain_matches_filter(map, loc, cond_filter, game_status, units, flat_tod, max_loop);
|
||||
}
|
||||
//handle [or]
|
||||
else if(cond_name == "or")
|
||||
{
|
||||
matches = matches ||
|
||||
terrain_matches_filter(map, loc, cond_filter, game_status, units, flat_tod, max_loop);
|
||||
}
|
||||
//handle [not]
|
||||
else if(cond_name == "not")
|
||||
{
|
||||
matches = matches &&
|
||||
!terrain_matches_filter(map, loc, cond_filter, game_status, units, flat_tod, max_loop);
|
||||
}
|
||||
const std::string& cond_name = *((*cond).first);
|
||||
const vconfig cond_filter(&(*((*cond).second)));
|
||||
|
||||
++cond;
|
||||
//handle [and]
|
||||
if(cond_name == "and")
|
||||
{
|
||||
matches = matches &&
|
||||
terrain_matches_filter(map, *i, cond_filter, game_status, units, flat_tod, max_loop);
|
||||
}
|
||||
//handle [or]
|
||||
else if(cond_name == "or")
|
||||
{
|
||||
matches = matches ||
|
||||
terrain_matches_filter(map, *i, cond_filter, game_status, units, flat_tod, max_loop);
|
||||
}
|
||||
//handle [not]
|
||||
else if(cond_name == "not")
|
||||
{
|
||||
matches = matches &&
|
||||
!terrain_matches_filter(map, *i, cond_filter, game_status, units, flat_tod, max_loop);
|
||||
}
|
||||
|
||||
++cond;
|
||||
}
|
||||
if(matches) {
|
||||
return true;
|
||||
}
|
||||
if(++loop_count > max_loop) {
|
||||
std::set<gamemap::location>::const_iterator temp = i;
|
||||
if(++temp != hexes.end()) {
|
||||
ERR_NG << "terrain_matches_filter: loop count greater than " << max_loop
|
||||
<< ", aborting\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
return false;
|
||||
}
|
||||
|
||||
void get_locations(const gamemap& map, std::set<gamemap::location>& locs, const vconfig& filter,
|
||||
const gamestatus& game_status, const unit_map& units, const bool flat_tod,
|
||||
const size_t max_loop)
|
||||
{
|
||||
std::vector<gamemap::location> xy_locs = parse_location_range(filter["x"],filter["y"], &map);
|
||||
if(xy_locs.empty()) {
|
||||
std::vector<gamemap::location> xy_vector = parse_location_range(filter["x"],filter["y"], &map);
|
||||
std::set<gamemap::location> xy_set(xy_vector.begin(), xy_vector.end());
|
||||
if(xy_set.empty()) {
|
||||
//consider all locations on the map
|
||||
for(int x=0; x < map.w(); x++) {
|
||||
for(int y=0; y < map.h(); y++) {
|
||||
xy_locs.push_back(gamemap::location(x,y));
|
||||
xy_set.insert(gamemap::location(x,y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -324,27 +336,25 @@ void get_locations(const gamemap& map, std::set<gamemap::location>& locs, const
|
|||
//remove any locations not found in the specified variable
|
||||
variable_info vi(filter["find_in"], false, variable_info::TYPE_CONTAINER);
|
||||
if(!vi.is_valid) {
|
||||
xy_locs.clear();
|
||||
xy_set.clear();
|
||||
} else if(vi.explicit_index) {
|
||||
gamemap::location test_loc(vi.as_container(),NULL);
|
||||
if(std::find(xy_locs.begin(), xy_locs.end(), test_loc) != xy_locs.end()) {
|
||||
xy_locs.clear();
|
||||
xy_locs.push_back(test_loc);
|
||||
if(xy_set.count(test_loc)) {
|
||||
xy_set.clear();
|
||||
xy_set.insert(test_loc);
|
||||
} else {
|
||||
xy_locs.clear();
|
||||
xy_set.clear();
|
||||
}
|
||||
} else {
|
||||
std::set<gamemap::location> findin_locs;
|
||||
variable_info::array_range a_range;
|
||||
for(a_range = vi.as_array(); a_range.first != a_range.second; ++a_range.first) {
|
||||
gamemap::location test_loc(**a_range.first,NULL);
|
||||
if(std::find(xy_locs.begin(), xy_locs.end(), test_loc) != xy_locs.end()) {
|
||||
if(xy_set.count(test_loc)) {
|
||||
findin_locs.insert(test_loc);
|
||||
}
|
||||
}
|
||||
xy_locs.clear();
|
||||
std::copy(findin_locs.begin(), findin_locs.end(),
|
||||
std::inserter(xy_locs, xy_locs.end()));
|
||||
xy_set.swap(findin_locs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,31 +363,26 @@ void get_locations(const gamemap& map, std::set<gamemap::location>& locs, const
|
|||
if(filter.has_child("filter_adjacent_location")) {
|
||||
tfc.adjacent_matches = new std::vector<std::set<gamemap::location> >();
|
||||
const vconfig::child_list& adj_filt = filter.get_children("filter_adjacent_location");
|
||||
for (unsigned i = 0; i < adj_filt.size() && i <= max_loop; ++i) {
|
||||
for (unsigned i = 0; i < adj_filt.size(); ++i) {
|
||||
std::set<gamemap::location> adj_set;
|
||||
get_locations(map, adj_set, adj_filt[i], game_status, units, flat_tod, max_loop);
|
||||
tfc.adjacent_matches->push_back(adj_set);
|
||||
if(i >= max_loop && i+1 < adj_filt.size()) {
|
||||
ERR_NG << "get_locations: loop count greater than " << max_loop
|
||||
<< ", aborting\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::vector<gamemap::location>::iterator loc_itor = xy_locs.begin();
|
||||
while(loc_itor != xy_locs.end()) {
|
||||
std::set<gamemap::location>::iterator loc_itor = xy_set.begin();
|
||||
while(loc_itor != xy_set.end()) {
|
||||
if(terrain_matches_internal(map, *loc_itor, filter, game_status, units, flat_tod, true, tfc)) {
|
||||
++loc_itor;
|
||||
} else {
|
||||
loc_itor = xy_locs.erase(loc_itor);
|
||||
xy_set.erase(loc_itor++);
|
||||
}
|
||||
}
|
||||
|
||||
//handle radius
|
||||
const size_t radius = minimum<size_t>(max_loop,
|
||||
lexical_cast_default<size_t>(filter["radius"], 0));
|
||||
if(filter.has_child("filter_radius")) {
|
||||
terrain_pred tp(map, filter.child("filter_radius"), game_status, units, flat_tod);
|
||||
get_tiles_radius(map, xy_locs, radius, locs, &tp);
|
||||
} else {
|
||||
get_tiles_radius(map, xy_locs, radius, locs);
|
||||
}
|
||||
|
||||
//handle [and], [or], and [not] with in-order precedence
|
||||
config::all_children_iterator cond = filter.get_config().ordered_begin();
|
||||
config::all_children_iterator cond_end = filter.get_config().ordered_end();
|
||||
|
@ -385,7 +390,7 @@ void get_locations(const gamemap& map, std::set<gamemap::location>& locs, const
|
|||
while(cond != cond_end)
|
||||
{
|
||||
//if there are no locations or [or] conditions left, go ahead and return empty
|
||||
if(locs.empty() && ors_left <= 0) {
|
||||
if(xy_set.empty() && ors_left <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -396,10 +401,10 @@ void get_locations(const gamemap& map, std::set<gamemap::location>& locs, const
|
|||
if(cond_name == "and") {
|
||||
std::set<gamemap::location> intersect_hexes;
|
||||
get_locations(map, intersect_hexes, cond_filter, game_status, units, flat_tod, max_loop);
|
||||
std::set<gamemap::location>::iterator intersect_itor = locs.begin();
|
||||
while(intersect_itor != locs.end()) {
|
||||
std::set<gamemap::location>::iterator intersect_itor = xy_set.begin();
|
||||
while(intersect_itor != xy_set.end()) {
|
||||
if(intersect_hexes.find(*intersect_itor) == intersect_hexes.end()) {
|
||||
locs.erase(*intersect_itor++);
|
||||
xy_set.erase(*intersect_itor++);
|
||||
} else {
|
||||
++intersect_itor;
|
||||
}
|
||||
|
@ -409,10 +414,10 @@ void get_locations(const gamemap& map, std::set<gamemap::location>& locs, const
|
|||
else if(cond_name == "or") {
|
||||
std::set<gamemap::location> union_hexes;
|
||||
get_locations(map, union_hexes, cond_filter, game_status, units, flat_tod, max_loop);
|
||||
//locs.insert(union_hexes.begin(), union_hexes.end()); //doesn't compile on MSVC
|
||||
//xy_set.insert(union_hexes.begin(), union_hexes.end()); //doesn't compile on MSVC
|
||||
std::set<gamemap::location>::iterator insert_itor = union_hexes.begin();
|
||||
while(insert_itor != union_hexes.end()) {
|
||||
locs.insert(*insert_itor++);
|
||||
xy_set.insert(*insert_itor++);
|
||||
}
|
||||
--ors_left;
|
||||
}
|
||||
|
@ -422,23 +427,35 @@ void get_locations(const gamemap& map, std::set<gamemap::location>& locs, const
|
|||
get_locations(map, removal_hexes, cond_filter, game_status, units, flat_tod, max_loop);
|
||||
std::set<gamemap::location>::iterator erase_itor = removal_hexes.begin();
|
||||
while(erase_itor != removal_hexes.end()) {
|
||||
locs.erase(*erase_itor++);
|
||||
xy_set.erase(*erase_itor++);
|
||||
}
|
||||
}
|
||||
|
||||
++cond;
|
||||
}
|
||||
|
||||
/*
|
||||
//restrict the potential number of locations to be returned
|
||||
if(locs.size() > max_loop + 1) {
|
||||
std::set<gamemap::location>::iterator erase_itor = locs.begin();
|
||||
for(unsigned i=0; i < max_loop + 1; ++i) {
|
||||
++erase_itor;
|
||||
}
|
||||
locs.erase(erase_itor, locs.end());
|
||||
if(xy_set.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//handle radius
|
||||
size_t radius = lexical_cast_default<size_t>(filter["radius"], 0);
|
||||
if(radius > max_loop) {
|
||||
ERR_NG << "get_locations: radius greater than " << max_loop
|
||||
<< ", restricting\n";
|
||||
radius = max_loop;
|
||||
}
|
||||
if(radius > 0) {
|
||||
xy_vector.clear();
|
||||
std::copy(xy_set.begin(),xy_set.end(),std::inserter(xy_vector,xy_vector.end()));
|
||||
if(filter.has_child("filter_radius")) {
|
||||
terrain_pred tp(map, filter.child("filter_radius"), game_status, units, flat_tod);
|
||||
get_tiles_radius(map, xy_vector, radius, locs, &tp);
|
||||
} else {
|
||||
get_tiles_radius(map, xy_vector, radius, locs);
|
||||
}
|
||||
} else {
|
||||
std::copy(xy_set.begin(),xy_set.end(),std::inserter(locs,locs.end()));
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue