diff --git a/data/schema/core/addons.cfg b/data/schema/core/addons.cfg index d6beb018d8e7..34631a5851d0 100644 --- a/data/schema/core/addons.cfg +++ b/data/schema/core/addons.cfg @@ -17,8 +17,14 @@ [tag] name="$side" max=0 - # TODO: This superclass should only be used if no_leader=no - super="units/$unit" + [if] + [not] + no_leader=yes + [/not] + [then] + super="units/$unit" + [/then] + [/if] {DEFAULT_KEY no_leader bool no} {SIMPLE_KEY recruit string} {DEFAULT_KEY gold int 100} diff --git a/data/schema/units/modifications.cfg b/data/schema/units/modifications.cfg index 2f26bd19f17c..a3680a7e5dda 100644 --- a/data/schema/units/modifications.cfg +++ b/data/schema/units/modifications.cfg @@ -12,7 +12,7 @@ key=apply_to [case] value=new_attack - super="units/unit_type/attack" + super="units/unit_type~core/attack" [/case] {FILTER_TAG "case" weapon value=remove_attacks} {FILTER_TAG "case" weapon ( diff --git a/src/serialization/tag.cpp b/src/serialization/tag.cpp index 46fa030e5d87..e5f9b8f359c8 100644 --- a/src/serialization/tag.cpp +++ b/src/serialization/tag.cpp @@ -215,13 +215,13 @@ void class_tag::add_link(const std::string& link) links_.emplace(name_link, link); } -const class_key* class_tag::find_key(const std::string& name, const config& match) const +const class_key* class_tag::find_key(const std::string& name, const config& match, bool ignore_super) const { // Check the conditions first, so that conditional definitions // override base definitions in the event of duplicates. for(auto& cond : conditions_) { if(cond.matches(match)) { - if(auto key = cond.find_key(name, match)) { + if(auto key = cond.find_key(name, match, true)) { return key; } } @@ -241,6 +241,23 @@ const class_key* class_tag::find_key(const std::string& name, const config& matc if(it_fuzzy != keys_.end()) { return &(it_fuzzy->second); } + + if(!ignore_super) { + for(auto& cond : conditions_) { + if(cond.matches(match)) { + // This results in a little redundancy (checking things twice) but at least it still works. + if(auto key = cond.find_key(name, match, false)) { + return key; + } + } + } + for(auto& super_tag : super_refs_) { + if(const class_key* found_key = super_tag->find_key(name, match)) { + return found_key; + } + } + } + return nullptr; } @@ -254,7 +271,7 @@ const std::string* class_tag::find_link(const std::string& name) const return nullptr; } -const class_tag* class_tag::find_tag(const std::string& fullpath, const class_tag& root, const config& match) const +const class_tag* class_tag::find_tag(const std::string& fullpath, const class_tag& root, const config& match, bool ignore_super) const { if(fullpath.empty()) { return nullptr; @@ -275,7 +292,7 @@ const class_tag* class_tag::find_tag(const std::string& fullpath, const class_ta // override base definitions in the event of duplicates. for(auto& cond : conditions_) { if(cond.matches(match)) { - if(auto tag = cond.find_tag(fullpath, root, match)) { + if(auto tag = cond.find_tag(fullpath, root, match, true)) { return tag; } } @@ -309,6 +326,22 @@ const class_tag* class_tag::find_tag(const std::string& fullpath, const class_ta } } + if(!ignore_super) { + for(auto& cond : conditions_) { + if(cond.matches(match)) { + // This results in a little redundancy (checking things twice) but at least it still works. + if(auto tag = cond.find_tag(fullpath, root, match, false)) { + return tag; + } + } + } + for(auto& super_tag : super_refs_) { + if(const class_tag* found_tag = super_tag->find_tag(fullpath, root, match)) { + return found_tag; + } + } + } + if(any_tag_) { return &any_tag; } @@ -448,37 +481,13 @@ void class_tag::add_tag(const std::string& path, const class_tag& tag, class_tag it_tags->second.add_tag(next_path, tag, root); } -void class_tag::append_super(const class_tag& tag, const std::string& path) -{ - // TODO: Ensure derived tag definitions override base tag definitions in the event of duplicates - add_keys(tag.keys_); - add_links(tag.links_); - add_conditions(tag.conditions_); - - for(const auto& t : tag.tags_) { - links_.erase(t.first); - if(t.second.is_fuzzy()) { - // Fuzzy tags won't work as links, so make a copy - // (Links just don't hold enough info for this to work.) - add_tag(t.second); - } else { - add_link(path + "/" + t.first); - } - } - if(tag.any_tag_) { - any_tag_ = true; - } -} - void class_tag::expand(class_tag& root) { - if(!super_.empty()) { - class_tag* super_tag = root.find_tag(super_, root, config()); + for(auto& super : utils::split(super_)) { + class_tag* super_tag = root.find_tag(super, root, config()); if(super_tag) { if(super_tag != this) { - super_tag->expand(root); - append_super(*super_tag, super_); - super_.clear(); + super_refs_.push_back(super_tag); } else { // TODO: Detect super cycles too! std::cerr << "the same" << super_tag->name_ << "\n"; diff --git a/src/serialization/tag.hpp b/src/serialization/tag.hpp index fab73dc98191..d82927233f7f 100644 --- a/src/serialization/tag.hpp +++ b/src/serialization/tag.hpp @@ -256,6 +256,7 @@ class class_tag using key_map = std::map; using link_map = std::map; using condition_list = std::vector; + using super_list = std::vector; private: void push_new_tag_conditions(std::queue q, const class_tag& tag); template> @@ -478,7 +479,7 @@ class class_tag } /** Returns pointer to child key. */ - const class_key* find_key(const std::string& name, const config& match) const; + const class_key* find_key(const std::string& name, const config& match, bool ignore_super = false) const; /** Returns pointer to child link. */ const std::string* find_link(const std::string& name) const; @@ -487,7 +488,7 @@ class class_tag * Returns pointer to tag using full path to it. * Also work with links */ - const class_tag* find_tag(const std::string& fullpath, const class_tag& root, const config& match) const; + const class_tag* find_tag(const std::string& fullpath, const class_tag& root, const config& match, bool ignore_super = false) const; /** Calls the expansion on each child. */ void expand_all(class_tag& root); @@ -551,6 +552,9 @@ class class_tag /** conditional partial matches */ condition_list conditions_; + /** super-tag references */ + super_list super_refs_; + /** whether this is a "fuzzy" tag. */ bool fuzzy_; @@ -591,10 +595,7 @@ class class_tag conditions_.insert(conditions_.end(), list.begin(), list.end()); } - /** Copies tags, keys and links of tag to this. */ - void append_super(const class_tag& tag, const std::string& super); - - /** Expands all "super" copying their data to this. */ + /** Expands all "super", storing direct references for easier access. */ void expand(class_tag& root); };