Move implementation of $teleport_unit into SLF so it can be passed to location formulas
This commit is contained in:
parent
d072661c94
commit
1bb750f649
4 changed files with 85 additions and 25 deletions
|
@ -34,6 +34,7 @@ Version 1.13.8+dev:
|
|||
Game Version dialog's clipboard function to stdout.
|
||||
* WFL Engine
|
||||
* Add owner key to terrain space callable, for villages
|
||||
* Location formulas in [tunnel] now have a teleport_unit variable
|
||||
* WML Engine
|
||||
* If ai_algorithm is used in [modify_side][ai], it now replaces the whole AI
|
||||
with the contents of [modify_side][ai], instead of appending these parameters.
|
||||
|
|
|
@ -109,8 +109,6 @@ void teleport_group::get_teleport_pair(
|
|||
, const unit& u
|
||||
, const bool ignore_units) const
|
||||
{
|
||||
const map_location &loc = u.get_location();
|
||||
|
||||
const filter_context * fc = resources::filter_con;
|
||||
assert(fc);
|
||||
|
||||
|
@ -122,15 +120,12 @@ void teleport_group::get_teleport_pair(
|
|||
vconfig source(cfg_.child_or_empty("source"), true);
|
||||
vconfig target(cfg_.child_or_empty("target"), true);
|
||||
const unit_filter ufilt(filter, resources::filter_con); //Note: Don't use the ignore units filter context here, only for the terrain filters. (That's how it worked before the filter contexts were introduced)
|
||||
if (ufilt.matches(u, loc)) {
|
||||
|
||||
scoped_xy_unit teleport_unit("teleport_unit", loc, resources::gameboard->units());
|
||||
|
||||
if (ufilt.matches(u)) {
|
||||
terrain_filter source_filter(source, fc);
|
||||
source_filter.get_locations(reversed_ ? loc_pair.second : loc_pair.first);
|
||||
source_filter.get_locations(reversed_ ? loc_pair.second : loc_pair.first, u);
|
||||
|
||||
terrain_filter target_filter(target, fc);
|
||||
target_filter.get_locations(reversed_ ? loc_pair.first : loc_pair.second);
|
||||
target_filter.get_locations(reversed_ ? loc_pair.first : loc_pair.second, u);
|
||||
}
|
||||
|
||||
if (ignore_units) {
|
||||
|
|
|
@ -97,7 +97,7 @@ namespace {
|
|||
};
|
||||
} //end anonymous namespace
|
||||
|
||||
bool terrain_filter::match_internal(const map_location& loc, const bool ignore_xy) const
|
||||
bool terrain_filter::match_internal(const map_location& loc, const unit* ref_unit, const bool ignore_xy) const
|
||||
{
|
||||
if (!this->fc_->get_disp_context().map().on_board_with_border(loc)) {
|
||||
return false;
|
||||
|
@ -326,7 +326,13 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x
|
|||
|
||||
if(cfg_.has_attribute("formula")) {
|
||||
try {
|
||||
const wfl::terrain_callable callable(fc_->get_disp_context(), loc);
|
||||
const wfl::terrain_callable main(fc_->get_disp_context(), loc);
|
||||
wfl::map_formula_callable callable(main.fake_ptr());
|
||||
if(ref_unit) {
|
||||
std::shared_ptr<wfl::unit_callable> ref(new wfl::unit_callable(*ref_unit));
|
||||
callable.add("teleport_unit", wfl::variant(ref));
|
||||
// It's not destroyed upon scope exit because the variant holds a reference
|
||||
}
|
||||
const wfl::formula form(cfg_["formula"]);
|
||||
if(!form.evaluate(callable).as_bool()) {
|
||||
return false;
|
||||
|
@ -342,7 +348,17 @@ bool terrain_filter::match_internal(const map_location& loc, const bool ignore_x
|
|||
return true;
|
||||
}
|
||||
|
||||
bool terrain_filter::match(const map_location& loc) const
|
||||
class filter_with_unit : public xy_pred {
|
||||
const terrain_filter& filt_;
|
||||
const unit& ref_;
|
||||
public:
|
||||
filter_with_unit(const terrain_filter& filt, const unit& ref) : filt_(filt), ref_(ref) {}
|
||||
bool operator()(const map_location& loc) const override {
|
||||
return filt_.match(loc, ref_);
|
||||
}
|
||||
};
|
||||
|
||||
bool terrain_filter::match_impl(const map_location& loc, const unit* ref_unit) const
|
||||
{
|
||||
if(cfg_["x"] == "recall" && cfg_["y"] == "recall") {
|
||||
return !fc_->get_disp_context().map().on_board(loc);
|
||||
|
@ -350,6 +366,15 @@ bool terrain_filter::match(const map_location& loc) const
|
|||
std::set<map_location> hexes;
|
||||
std::vector<map_location> loc_vec(1, loc);
|
||||
|
||||
std::unique_ptr<scoped_wml_variable> ref_unit_var;
|
||||
if(ref_unit) {
|
||||
if(fc_->get_disp_context().map().on_board(ref_unit->get_location())) {
|
||||
ref_unit_var.reset(new scoped_xy_unit("teleport_unit", ref_unit->get_location(), fc_->get_disp_context().units()));
|
||||
} else {
|
||||
// Possible TODO: Support recall list units?
|
||||
}
|
||||
}
|
||||
|
||||
//handle radius
|
||||
size_t radius = cfg_["radius"].to_size_t(0);
|
||||
if(radius > max_loop_) {
|
||||
|
@ -361,7 +386,11 @@ 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(fc_->get_disp_context().map(), loc_vec, radius, hexes, false, r_filter);
|
||||
if(ref_unit) {
|
||||
get_tiles_radius(fc_->get_disp_context().map(), loc_vec, radius, hexes, false, filter_with_unit(r_filter, *ref_unit));
|
||||
} else {
|
||||
get_tiles_radius(fc_->get_disp_context().map(), loc_vec, radius, hexes, false, r_filter);
|
||||
}
|
||||
} else {
|
||||
get_tiles_radius(fc_->get_disp_context().map(), loc_vec, radius, hexes);
|
||||
}
|
||||
|
@ -369,7 +398,7 @@ bool terrain_filter::match(const map_location& loc) const
|
|||
size_t loop_count = 0;
|
||||
std::set<map_location>::const_iterator i;
|
||||
for(i = hexes.begin(); i != hexes.end(); ++i) {
|
||||
bool matches = match_internal(*i, false);
|
||||
bool matches = match_internal(*i, ref_unit, false);
|
||||
|
||||
//handle [and], [or], and [not] with in-order precedence
|
||||
vconfig::all_children_iterator cond = cfg_.ordered_begin();
|
||||
|
@ -382,17 +411,17 @@ bool terrain_filter::match(const map_location& loc) const
|
|||
//handle [and]
|
||||
if(cond_name == "and")
|
||||
{
|
||||
matches = matches && terrain_filter(cond_cfg, *this)(*i);
|
||||
matches = matches && terrain_filter(cond_cfg, *this).match_impl(*i, ref_unit);
|
||||
}
|
||||
//handle [or]
|
||||
else if(cond_name == "or")
|
||||
{
|
||||
matches = matches || terrain_filter(cond_cfg, *this)(*i);
|
||||
matches = matches || terrain_filter(cond_cfg, *this).match_impl(*i, ref_unit);
|
||||
}
|
||||
//handle [not]
|
||||
else if(cond_name == "not")
|
||||
{
|
||||
matches = matches && !terrain_filter(cond_cfg, *this)(*i);
|
||||
matches = matches && !terrain_filter(cond_cfg, *this).match_impl(*i, ref_unit);
|
||||
}
|
||||
++cond;
|
||||
}
|
||||
|
@ -473,8 +502,17 @@ struct cfg_to_loc
|
|||
map_location operator()(const config& cfg) const { return map_location(cfg, nullptr); }
|
||||
typedef map_location result_type;
|
||||
};
|
||||
void terrain_filter::get_locations(std::set<map_location>& locs, bool with_border) const
|
||||
void terrain_filter::get_locs_impl(std::set<map_location>& locs, const unit* ref_unit, bool with_border) const
|
||||
{
|
||||
std::unique_ptr<scoped_wml_variable> ref_unit_var;
|
||||
if(ref_unit) {
|
||||
if(fc_->get_disp_context().map().on_board(ref_unit->get_location())) {
|
||||
ref_unit_var.reset(new scoped_xy_unit("teleport_unit", ref_unit->get_location(), fc_->get_disp_context().units()));
|
||||
} else {
|
||||
// Possible TODO: Support recall list units?
|
||||
}
|
||||
}
|
||||
|
||||
std::set<map_location> match_set;
|
||||
|
||||
// See if the caller provided an override to with_border
|
||||
|
@ -540,10 +578,10 @@ void terrain_filter::get_locations(std::set<map_location>& locs, bool with_borde
|
|||
}
|
||||
std::set<map_location>::iterator loc_itor = match_set.begin();
|
||||
while(loc_itor != match_set.end()) {
|
||||
if(match_internal(*loc_itor, true)) {
|
||||
if(match_internal(*loc_itor, ref_unit, true)) {
|
||||
++loc_itor;
|
||||
} else {
|
||||
match_set.erase(loc_itor++);
|
||||
loc_itor = match_set.erase(loc_itor);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,13 +39,37 @@ public:
|
|||
terrain_filter(const terrain_filter &other);
|
||||
terrain_filter& operator=(const terrain_filter &other);
|
||||
|
||||
//match: returns true if and only if the given location matches this filter
|
||||
bool match(const map_location& loc) const;
|
||||
/// @param loc The location to test
|
||||
/// @returns true if and only if the given location matches this filter
|
||||
bool match(const map_location& loc) const {
|
||||
return match_impl(loc, nullptr);
|
||||
}
|
||||
|
||||
/// @param loc The location to test
|
||||
/// @param ref_unit A reference unit for the $teleport_unit auto-stored variable
|
||||
/// @param unit_loc The reference unit's apparent location for this filter
|
||||
/// @returns true if and only if the given location matches this filter
|
||||
bool match(const map_location& loc, const unit& ref_unit) const {
|
||||
return match_impl(loc, &ref_unit);
|
||||
}
|
||||
|
||||
virtual bool operator()(const map_location& loc) const { return this->match(loc); }
|
||||
|
||||
//get_locations: gets all locations on the map that match this filter
|
||||
// @param locs - out parameter containing the results
|
||||
void get_locations(std::set<map_location>& locs, bool with_border=false) const;
|
||||
/// gets all locations on the map that match this filter
|
||||
/// @param[out] locs set to store the results in
|
||||
/// @param[in] with_border whether to include the borders
|
||||
void get_locations(std::set<map_location>& locs, bool with_border=false) const {
|
||||
return get_locs_impl(locs, nullptr, with_border);
|
||||
}
|
||||
|
||||
/// gets all locations on the map that match this filter
|
||||
/// @param[out] locs set to store the results in
|
||||
/// @param[in] with_border whether to include the borders
|
||||
/// @param[in] ref_unit A reference unit for the $teleport_unit auto-stored variable
|
||||
/// @param[in] unit_loc The reference unit's apparent location for this filter
|
||||
void get_locations(std::set<map_location>& locs, const unit& ref_unit, bool with_border=false) const {
|
||||
return get_locs_impl(locs, &ref_unit, with_border);
|
||||
}
|
||||
|
||||
//restrict: limits the allowed radius size and also limits nesting
|
||||
// The purpose to limit the time spent for WML handling
|
||||
|
@ -58,7 +82,9 @@ public:
|
|||
config to_config() const;
|
||||
friend class terrain_filterimpl;
|
||||
private:
|
||||
bool match_internal(const map_location& loc, const bool ignore_xy) const;
|
||||
bool match_impl(const map_location& loc, const unit* ref_unit) const;
|
||||
void get_locs_impl(std::set<map_location>& locs, const unit* ref_unit, bool with_border) const;
|
||||
bool match_internal(const map_location& loc, const unit* ref_unit, const bool ignore_xy) const;
|
||||
|
||||
const vconfig cfg_; //config contains WML for a Standard Location Filter
|
||||
const filter_context * fc_;
|
||||
|
|
Loading…
Add table
Reference in a new issue