new tag [insert_tag], as discussed on wiki/FutureWML

* note: there are ways you can make this crash with bad WML
  these will be safeguarded against further in a later update
This commit is contained in:
Patrick Parker 2008-04-13 06:43:09 +00:00
parent e7a5e57055
commit 1348cf80d2
7 changed files with 239 additions and 49 deletions

View file

@ -44,6 +44,7 @@ Version 1.5.0-svn:
* Removed Wesbowl
* Merged 4p A New Land by Bob_the_Mighty
* WML engine:
* new tag [insert_tag] to place dynamic WML content
* Fixed most C++ probes for boolean WML attributes to use
utils::string_bool() rather than true/false or yes/no string comparisons;
as a result, they should accept true non-zero values, "on", "yes" or "true"

View file

@ -559,10 +559,12 @@ Xu ,Xu , Qxu , Qxu , Ql , Ql
[filter]
x,y=9,3
[/filter]
[endlevel]
result="victory"
bonus=yes
[/endlevel]
{VARIABLE endlevel_test.result "victory"}
{VARIABLE endlevel_test.bonus "yes"}
[insert_tag]
name=endlevel
variable=endlevel_test
[/insert_tag]
[/event]
[event]

View file

@ -282,12 +282,12 @@ bool conditional_passed(const unit_map* units,
// Handle [and], [or], and [not] with in-order precedence
int or_count = 0;
config::all_children_iterator cond_i = cond.get_config().ordered_begin();
config::all_children_iterator cond_end = cond.get_config().ordered_end();
vconfig::all_children_iterator cond_i = cond.ordered_begin();
vconfig::all_children_iterator cond_end = cond.ordered_end();
while(cond_i != cond_end)
{
const std::string& cond_name = *((*cond_i).first);
const vconfig cond_filter(&(*((*cond_i).second)));
const std::string& cond_name = cond_i.get_key();
const vconfig& cond_filter = cond_i.get_child();
// Handle [and]
if(cond_name == "and")
@ -401,7 +401,7 @@ public:
if (!kids.empty())
return kids;
else
return cfg_.get_children("special_filter");
return cfg_.get_children("special_filter");
}
@ -417,7 +417,7 @@ public:
if (!kids.empty())
return kids;
else
return cfg_.get_children("special_filter_second");
return cfg_.get_children("special_filter_second");
}
bool handle_event(const queued_event& event_info,
@ -2812,13 +2812,11 @@ bool event_handler::handle_event(const queued_event& event_info, const vconfig c
if(cfg.null()) {
cfg = cfg_;
}
for(config::all_children_iterator i = cfg.get_config().ordered_begin();
i != cfg.get_config().ordered_end(); ++i) {
const std::pair<const std::string*,const config*> item = *i;
for(vconfig::all_children_iterator i = cfg.ordered_begin();
i != cfg.ordered_end(); ++i) {
//mutated and skip_messages will be modified
handle_event_command(event_info, *item.first, vconfig(item.second), mutated, skip_messages);
handle_event_command(event_info, i.get_key(), i.get_child(), mutated, skip_messages);
}
// We do this once the event has completed any music alterations
@ -2940,12 +2938,12 @@ bool matches_special_filter(const config* cfg, const vconfig filter)
}
// Handle [and], [or], and [not] with in-order precedence
config::all_children_iterator cond_i = filter.get_config().ordered_begin();
config::all_children_iterator cond_end = filter.get_config().ordered_end();
vconfig::all_children_iterator cond_i = filter.ordered_begin();
vconfig::all_children_iterator cond_end = filter.ordered_end();
while(cond_i != cond_end)
{
const std::string& cond_name = *((*cond_i).first);
const vconfig cond_filter(&(*((*cond_i).second)));
const std::string& cond_name = cond_i.get_key();
const vconfig& cond_filter = cond_i.get_child();
// Handle [and]
if(cond_name == "and")

View file

@ -33,7 +33,7 @@
#define ERR_NG LOG_STREAM(err, engine)
terrain_filter::terrain_filter(const vconfig& cfg, const gamemap& map,
terrain_filter::terrain_filter(const vconfig& cfg, const gamemap& map,
const gamestatus& game_status, const unit_map& units, const bool flat_tod,
const size_t max_loop) : cfg_(cfg), map_(map), status_(game_status), units_(units)
{
@ -48,12 +48,12 @@ terrain_filter::terrain_filter(const vconfig& cfg, const terrain_filter& origina
flatten(original.flat_);
}
terrain_filter::terrain_filter(const terrain_filter& other) :
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_),
map_(other.map_),
status_(other.status_),
map_(other.map_),
status_(other.status_),
units_(other.units_)
{
restrict(other.max_loop_);
@ -72,8 +72,8 @@ terrain_filter& terrain_filter::operator=(const terrain_filter& other)
namespace {
struct cfg_isor {
bool operator() (std::pair<const std::string*,const config*> val) {
return *(val.first) == "or";
bool operator() (std::pair<const std::string,const vconfig> val) {
return val.first == "or";
}
};
} //end anonymous namespace
@ -177,7 +177,7 @@ bool terrain_filter::match_internal(const gamemap::location& loc, const bool ign
}
}
static std::vector<std::pair<int,int> > default_counts = utils::parse_ranges("1-6");
std::vector<std::pair<int,int> > counts = (*i).has_attribute("count")
std::vector<std::pair<int,int> > counts = (*i).has_attribute("count")
? utils::parse_ranges((*i)["count"]) : default_counts;
std::vector<std::pair<int,int> >::const_iterator count, count_end = counts.end();
bool count_matches = false;
@ -278,12 +278,12 @@ bool terrain_filter::match(const gamemap::location& loc)
bool matches = match_internal(*i, false);
//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();
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).first);
const vconfig cond_cfg(&(*((*cond).second)));
const std::string& cond_name = cond.get_key();
const vconfig& cond_cfg = cond.get_child();
//handle [and]
if(cond_name == "and")
@ -383,8 +383,8 @@ void terrain_filter::get_locations(std::set<gamemap::location>& locs)
}
//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();
vconfig::all_children_iterator cond = cfg_.ordered_begin();
vconfig::all_children_iterator cond_end = cfg_.ordered_end();
int ors_left = std::count_if(cond, cond_end, cfg_isor());
while(cond != cond_end)
{
@ -393,8 +393,8 @@ void terrain_filter::get_locations(std::set<gamemap::location>& locs)
return;
}
const std::string& cond_name = *((*cond).first);
const vconfig cond_cfg(&(*((*cond).second)));
const std::string& cond_name = cond.get_key();
const vconfig& cond_cfg = cond.get_child();
//handle [and]
if(cond_name == "and") {

View file

@ -822,13 +822,13 @@ bool unit::matches_filter(const vconfig& cfg, const gamemap::location& loc, bool
}
// 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();
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).first);
const vconfig cond_filter(&(*((*cond).second)));
const std::string& cond_name = cond.get_key();
const vconfig& cond_filter = cond.get_child();
// Handle [and]
if(cond_name == "and") {

View file

@ -37,24 +37,26 @@ namespace
}
vconfig::vconfig() :
cfg_(NULL)
cfg_(NULL), volatile_(false)
{
}
vconfig::vconfig(const config* cfg) :
cfg_(cfg)
vconfig::vconfig(const config* cfg, bool is_volatile) :
cfg_(cfg), volatile_(is_volatile)
{
}
vconfig& vconfig::operator=(const vconfig cfg)
{
cfg_ = cfg.cfg_;
volatile_ = cfg.volatile_;
return *this;
}
vconfig& vconfig::operator=(const config* cfg)
{
cfg_ = cfg;
//is volatile? assume current setting
return *this;
}
@ -69,29 +71,97 @@ const config vconfig::get_parsed_config() const
}
for(config::all_children_iterator child = cfg_->ordered_begin();
child != cfg_->ordered_end(); ++child) {
child != cfg_->ordered_end(); ++child)
{
res.add_child(*(*child).first, vconfig((*child).second).get_parsed_config());
const std::string &child_key = *(*child).first;
if(child_key == "insert_tag") {
vconfig insert_cfg(child->second);
const t_string& name = insert_cfg["name"];
variable_info vinfo(insert_cfg["variable"], true, variable_info::TYPE_CONTAINER);
if(vinfo.explicit_index) {
res.add_child(name, vconfig(&(vinfo.as_container()), true).get_parsed_config());
} else {
variable_info::array_range range = vinfo.as_array();
if(range.first == range.second) {
res.add_child(name); //add empty tag
}
while(range.first != range.second) {
res.add_child(name, vconfig(*range.first++, true).get_parsed_config());
}
}
} else {
res.add_child(child_key, vconfig((*child).second).get_parsed_config());
}
}
return res;
}
vconfig::child_list vconfig::get_children(const std::string& key) const
{
const config::child_list& list = cfg_->get_children(key);
vconfig::child_list res(list.size());
std::copy(list.begin(), list.end(),res.begin());
vconfig::child_list res;
for(config::all_children_iterator child = cfg_->ordered_begin();
child != cfg_->ordered_end(); ++child)
{
const std::string &child_key = *(*child).first;
if(child_key == key) {
res.push_back(vconfig(child->second, volatile_));
} else if(child_key == "insert_tag") {
vconfig insert_cfg(child->second);
if(insert_cfg["name"] == key) {
variable_info vinfo(insert_cfg["variable"], true, variable_info::TYPE_CONTAINER);
if(vinfo.explicit_index) {
res.push_back(vconfig(&(vinfo.as_container()), true));
} else {
variable_info::array_range range = vinfo.as_array();
if(range.first == range.second) {
//push back an empty (volatile) tag
res.push_back(vconfig(&(vinfo.as_container()), true));
}
while(range.first != range.second) {
res.push_back(vconfig(*range.first++, true));
}
}
}
}
}
return res;
}
vconfig vconfig::child(const std::string& key) const
{
return vconfig(cfg_->child(key));
const config *natural = cfg_->child(key);
if(natural)
{
return vconfig(natural, volatile_);
}
for(config::const_child_itors chitors = cfg_->child_range("insert_tag");
chitors.first != chitors.second; ++chitors.first)
{
vconfig insert_cfg(*chitors.first);
if(insert_cfg["name"] == key) {
variable_info vinfo(insert_cfg["variable"], true, variable_info::TYPE_CONTAINER);
return vconfig(&(vinfo.as_container()), true);
}
}
return vconfig();
}
bool vconfig::has_child(const std::string& key) const
{
return (cfg_->child(key) != NULL);
if(cfg_->child(key) != NULL) {
return true;
}
for(config::const_child_itors chitors = cfg_->child_range("insert_tag");
chitors.first != chitors.second; ++chitors.first)
{
vconfig insert_cfg(*chitors.first);
if(insert_cfg["name"] == key) {
return true;
}
}
return false;
}
const t_string vconfig::expand(const std::string& key) const
@ -106,6 +176,91 @@ const t_string vconfig::expand(const std::string& key) const
return t_string(val);
}
vconfig::all_children_iterator::all_children_iterator(config::all_children_iterator i)
: i_(i), inner_index_(0), index_offset_(0)
{
}
vconfig::all_children_iterator& vconfig::all_children_iterator::operator++()
{
if(i_.get_key() == "insert_tag") {
variable_info vinfo(vconfig(&i_.get_child())["variable"], false, variable_info::TYPE_CONTAINER);
if(vinfo.is_valid && !vinfo.explicit_index) {
variable_info::array_range range = vinfo.as_array();
if(range.first != range.second && range.first + (++inner_index_) != range.second) {
++index_offset_;
return *this;
}
}
}
++i_;
inner_index_ = 0;
return *this;
}
vconfig::all_children_iterator vconfig::all_children_iterator::operator++(int)
{
vconfig::all_children_iterator i = *this;
this->operator++();
return i;
}
std::pair<const std::string,const vconfig> vconfig::all_children_iterator::operator*() const
{
return std::make_pair<const std::string, const vconfig>(get_key(), get_child());
}
vconfig::all_children_iterator::pointer vconfig::all_children_iterator::operator->() const
{
return pointer(new std::pair<const std::string, const vconfig>(get_key(), get_child()));
}
const std::string vconfig::all_children_iterator::get_key() const
{
const std::string& key = i_.get_key();
if(key == "insert_tag") {
return vconfig(&i_.get_child())["name"];
}
return key;
}
const vconfig vconfig::all_children_iterator::get_child() const
{
if(i_.get_key() == "insert_tag") {
variable_info vinfo(vconfig(&i_.get_child())["variable"], true, variable_info::TYPE_CONTAINER);
if(inner_index_ == 0) {
return vconfig(&vinfo.as_container(), true);
}
return vconfig(*(vinfo.as_array().first + inner_index_), true);
}
return vconfig(&i_.get_child());
}
size_t vconfig::all_children_iterator::get_index() const
{
return i_.get_index() + index_offset_;
}
bool vconfig::all_children_iterator::operator==(all_children_iterator i) const
{
return (i_ == i.i_ && inner_index_ == i.inner_index_);
}
bool vconfig::all_children_iterator::operator!=(all_children_iterator i) const
{
return (i_ != i.i_ || inner_index_ != i.inner_index_);
}
vconfig::all_children_iterator vconfig::ordered_begin() const
{
return all_children_iterator(cfg_->ordered_begin());
}
vconfig::all_children_iterator vconfig::ordered_end() const
{
return all_children_iterator(cfg_->ordered_end());
}
namespace variable
{
manager::manager(game_state* repository)

View file

@ -33,7 +33,7 @@ class vconfig
{
public:
vconfig();
vconfig(const config* cfg);
vconfig(const config* cfg, bool is_volatile=false);
vconfig& operator=(const vconfig cfg);
vconfig& operator=(const config* cfg);
@ -52,9 +52,43 @@ public:
const t_string& get_attribute(const std::string& key) const { return (*cfg_)[key]; }
bool has_attribute(const std::string& key) const { return cfg_->has_attribute(key); }
bool empty() const { return (null() || cfg_->empty()); }
bool is_volatile() const { return volatile_; }
struct all_children_iterator {
typedef std::pair<const std::string, const vconfig> value_type;
typedef std::forward_iterator_tag iterator_category;
typedef int difference_type;
typedef std::auto_ptr<value_type> pointer;
typedef value_type& reference;
typedef config::all_children_iterator Itor;
explicit all_children_iterator(Itor i=Itor());
all_children_iterator& operator++();
all_children_iterator operator++(int);
value_type operator*() const;
pointer operator->() const;
const std::string get_key() const;
size_t get_index() const;
const vconfig get_child() const;
bool operator==(all_children_iterator i) const;
bool operator!=(all_children_iterator i) const;
private:
Itor i_;
unsigned inner_index_;
unsigned index_offset_;
};
//! In-order iteration over all children.
all_children_iterator ordered_begin() const;
all_children_iterator ordered_end() const;
private:
const config* cfg_;
bool volatile_;
};
namespace variable