diff --git a/src/unit.cpp b/src/unit.cpp index c140c5ec512..c4d4ffd356f 100644 --- a/src/unit.cpp +++ b/src/unit.cpp @@ -838,19 +838,15 @@ void unit::advance_to(const config &old_cfg, const unit_type &u_type, if ( new_type.movement_type().get_parent() ) { new_cfg.merge_with(new_type.movement_type().get_parent()->get_cfg()); + // Convert movement type's "flies" to unit's "flying". + if ( const config::attribute_value * flies = new_cfg.get("flies") ) { + new_cfg["flying"] = flies->to_bool(); + new_cfg.remove_attribute("flies"); + } } - new_cfg.merge_with(new_type.get_cfg()); - - // Remove "pure" unit_type attributes (attributes that do not get directly - // copied to units; some do get copied, but under different keys). - static char const *unit_type_attrs[] = { "attacks", "die_sound", - "experience", "flies", "hide_help", "hitpoints", "id", - "ignore_race_traits", "inherit", "movement", "movement_type", - "name", "num_traits", "variation_name" }; - BOOST_FOREACH(const char *attr, unit_type_attrs) { - new_cfg.remove_attribute(attr); - } + // Inherit from the new unit type. + new_cfg.merge_with(new_type.get_cfg_for_units()); // If unit has specific profile, remember it and keep it after advancing std::string profile = old_cfg["profile"].str(); @@ -867,8 +863,6 @@ void unit::advance_to(const config &old_cfg, const unit_type &u_type, } cfg_.swap(new_cfg); - cfg_.clear_children("male"); - cfg_.clear_children("female"); // NOTE: There should be no need to access old_cfg (or new_cfg) after this // line. Particularly since the swap might have affected old_cfg. diff --git a/src/unit_types.cpp b/src/unit_types.cpp index 29a79a2248a..b78f8ed88bf 100644 --- a/src/unit_types.cpp +++ b/src/unit_types.cpp @@ -620,6 +620,8 @@ int defense_modifier_internal(defense_cache &defense_mods, unit_type::unit_type(const unit_type& o) : cfg_(o.cfg_), + unit_cfg_(), // Not copied; will be re-created if needed. + built_unit_cfg_(false), id_(o.id_), debug_id_(o.debug_id_), base_id_(o.base_id_), @@ -671,6 +673,8 @@ unit_type::unit_type(const unit_type& o) : unit_type::unit_type(const config &cfg, const std::string & parent_id) : cfg_(cfg), + unit_cfg_(), + built_unit_cfg_(false), id_(cfg_.has_attribute("id") ? cfg_["id"].str() : parent_id), debug_id_(), base_id_(!parent_id.empty() ? parent_id : id_), @@ -1310,6 +1314,33 @@ std::vector unit_type::variations() const } +/** + * Generates (and returns) a trimmed config suitable for use with units. + */ +const config & unit_type::build_unit_cfg() const +{ + // We start with everything. + unit_cfg_ = cfg_; + + // Remove "pure" unit_type attributes (attributes that do not get directly + // copied to units; some do get copied, but under different keys). + static char const *unit_type_attrs[] = { "attacks", "die_sound", + "experience", "flies", "hide_help", "hitpoints", "id", + "ignore_race_traits", "inherit", "movement", "movement_type", + "name", "num_traits", "variation_name" }; + BOOST_FOREACH(const char *attr, unit_type_attrs) { + unit_cfg_.remove_attribute(attr); + } + + // Remove gendered children. + unit_cfg_.clear_children("male"); + unit_cfg_.clear_children("female"); + + built_unit_cfg_ = true; + return unit_cfg_; +} + + /* ** unit_type_data ** */ diff --git a/src/unit_types.hpp b/src/unit_types.hpp index 288960ee4e0..edd3f07f1ca 100644 --- a/src/unit_types.hpp +++ b/src/unit_types.hpp @@ -327,11 +327,19 @@ public: const std::vector& portraits() const { return portraits_; } const config &get_cfg() const { return cfg_; } + /// Returns a trimmed config suitable for use with units. + const config & get_cfg_for_units() const + { return built_unit_cfg_ ? unit_cfg_ : build_unit_cfg(); } +private: + /// Generates (and returns) a trimmed config suitable for use with units. + const config & build_unit_cfg() const; private: void operator=(const unit_type& o); const config &cfg_; + mutable config unit_cfg_; /// Generated as needed via get_cfg_for_units(). + mutable bool built_unit_cfg_; std::string id_; std::string debug_id_; /// A suffix for id_, used when logging messages.