Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "global.hpp"
00022
00023 #include "race.hpp"
00024
00025 #include "log.hpp"
00026 #include "random.hpp"
00027 #include "simple_rng.hpp"
00028
00029 static const config &empty_traits() {
00030 static config cfg;
00031 return cfg;
00032 }
00033
00034 static const config &empty_topics() {
00035 static config cfg;
00036 return cfg;
00037 }
00038
00039 static void add_prefixes(const wide_string& str, size_t length, markov_prefix_map& res)
00040 {
00041 for(size_t i = 0; i <= str.size(); ++i) {
00042 const size_t start = i > length ? i - length : 0;
00043 const wide_string key(str.begin() + start, str.begin() + i);
00044 const wchar_t c = i != str.size() ? str[i] : 0;
00045 res[key].push_back(c);
00046 }
00047 }
00048
00049 static markov_prefix_map markov_prefixes(const std::vector<std::string>& items, size_t length)
00050 {
00051 markov_prefix_map res;
00052
00053 for(std::vector<std::string>::const_iterator i = items.begin(); i != items.end(); ++i) {
00054 add_prefixes(utils::string_to_wstring(*i),length,res);
00055 }
00056
00057 return res;
00058 }
00059
00060 static wide_string markov_generate_name(const markov_prefix_map& prefixes,
00061 size_t chain_size, size_t max_len, rand_rng::simple_rng* rng)
00062 {
00063 if(chain_size == 0)
00064 return wide_string();
00065
00066 wide_string prefix, res;
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 std::vector<int> random(max_len);
00079 size_t j = 0;
00080 for(; j < max_len; ++j) {
00081 random[j] = rng ? rng->get_next_random() : get_random_nocheck();
00082 }
00083
00084 j = 0;
00085 while(res.size() < max_len) {
00086 const markov_prefix_map::const_iterator i = prefixes.find(prefix);
00087 if(i == prefixes.end() || i->second.empty()) {
00088 return res;
00089 }
00090
00091 const wchar_t c = i->second[random[j++]%i->second.size()];
00092 if(c == 0) {
00093 return res;
00094 }
00095
00096 res.resize(res.size()+1);
00097 res[res.size()-1] = c;
00098 prefix.resize(prefix.size()+1);
00099 prefix[prefix.size()-1] = c;
00100 while(prefix.size() > chain_size) {
00101 prefix.erase(prefix.begin());
00102 }
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 wide_string originalRes = res;
00115 int prefixLen;
00116 while(!res.empty()) {
00117 prefixLen = chain_size < res.size() ? chain_size : res.size();
00118 prefix = wide_string(res.end() - prefixLen, res.end());
00119
00120 const markov_prefix_map::const_iterator i = prefixes.find(prefix);
00121 if (i == prefixes.end() || i->second.empty()) {
00122 return res;
00123 }
00124 if (std::find(i->second.begin(), i->second.end(), static_cast<wchar_t>(0))
00125 != i->second.end()) {
00126
00127 return res;
00128 }
00129
00130
00131 res.pop_back();
00132 }
00133
00134
00135
00136
00137 return originalRes;
00138 }
00139
00140 unit_race::unit_race() :
00141 cfg_(),
00142 id_(),
00143 plural_name_(),
00144 description_(),
00145 ntraits_(0),
00146 chain_size_(0),
00147 traits_(empty_traits().child_range("trait")),
00148 topics_(empty_topics().child_range("topic")),
00149 global_traits_(true),
00150 undead_variation_()
00151 {
00152 name_[MALE] = "";
00153 name_[FEMALE] = "";
00154 }
00155
00156 unit_race::unit_race(const config& cfg) :
00157 cfg_(cfg),
00158 id_(cfg["id"]),
00159 plural_name_(cfg["plural_name"].t_str()),
00160 description_(cfg["description"].t_str()),
00161 ntraits_(cfg["num_traits"]),
00162 chain_size_(cfg["markov_chain_size"]),
00163 traits_(cfg.child_range("trait")),
00164 topics_(cfg.child_range("topic")),
00165 global_traits_(!cfg["ignore_global_traits"].to_bool()),
00166 undead_variation_(cfg["undead_variation"])
00167
00168 {
00169 if (id_.empty()) {
00170 lg::wml_error << "[race] '" << cfg["name"] << "' is missing an id field.";
00171 }
00172 if (plural_name_.empty()) {
00173 lg::wml_error << "[race] '" << cfg["name"] << "' is missing a plural_name field.";
00174 plural_name_ = (cfg["name"]);
00175 }
00176
00177 name_[MALE] = cfg["male_name"];
00178 if(name_[MALE].empty()) {
00179 name_[MALE] = (cfg["name"]);
00180 }
00181 name_[FEMALE] = cfg["female_name"];
00182 if(name_[FEMALE].empty()) {
00183 name_[FEMALE] = (cfg["name"]);
00184 }
00185
00186 if(chain_size_ <= 0)
00187 chain_size_ = 2;
00188
00189
00190 next_[MALE] = markov_prefixes(utils::split(cfg["male_names"]), chain_size_);
00191 next_[FEMALE] = markov_prefixes(utils::split(cfg["female_names"]), chain_size_);
00192 }
00193
00194 std::string unit_race::generate_name(
00195 unit_race::GENDER gender, rand_rng::simple_rng* rng) const
00196 {
00197 return utils::wstring_to_string(
00198 markov_generate_name(next_[gender], chain_size_, 12, rng));
00199 }
00200
00201 bool unit_race::uses_global_traits() const
00202 {
00203 return global_traits_;
00204 }
00205
00206 const config::const_child_itors &unit_race::additional_traits() const
00207 {
00208 return traits_;
00209 }
00210
00211 const config::const_child_itors &unit_race::additional_topics() const
00212 {
00213 return topics_;
00214 }
00215
00216 unsigned int unit_race::num_traits() const { return ntraits_; }
00217
00218 std::string const& gender_string(unit_race::GENDER gender) {
00219 static const std::string female_string = "female";
00220 static const std::string male_string = "male";
00221 switch(gender) {
00222 case unit_race::FEMALE:
00223 return female_string;
00224 default:
00225 case unit_race::MALE:
00226 return male_string;
00227 }
00228 }
00229
00230 unit_race::GENDER string_gender(const std::string& str, unit_race::GENDER def) {
00231 if(str == gender_string(unit_race::MALE)) {
00232 return unit_race::MALE;
00233 } else if(str == gender_string(unit_race::FEMALE)) {
00234 return unit_race::FEMALE;
00235 }
00236 return def;
00237 }