Improvements in the map and name generators
- Implement a way to escape special characters {|} in the CFG generator - Eliminate null pointers to name generators - Invalid generators now throw exceptions - Name generating rules for different terrain elements can now be specified (The defaults in english.cfg are still used)
This commit is contained in:
parent
a8f625fc8a
commit
f96f86245e
17 changed files with 415 additions and 269 deletions
|
@ -155,7 +155,7 @@ Version 1.13.4+dev:
|
|||
and [deprecated_message] tags now use this.
|
||||
* New wesnoth.name_generator function builds a name generator and returns
|
||||
it as a callable userdata. Both the original Markov chain generator
|
||||
and the new context free gramamr generator are supported
|
||||
and the new context free grammar generator are supported
|
||||
* WML tables defined in Lua now accept string keys with array values
|
||||
(where "array" is a table whose keys are all integers). This joins
|
||||
the elements of the array with commas and produces a single string
|
||||
|
@ -279,6 +279,9 @@ Version 1.13.4+dev:
|
|||
* pair() function that produces a key-value pair suitable for
|
||||
passing to tomap() - this also means key-value pairs are now
|
||||
serializable (relevant in FormulaAI)
|
||||
* Map generator engine:
|
||||
* makes now use of the new context free grammar name generator
|
||||
* ported name generation from english.cfg to [naming]
|
||||
* Bugfixes:
|
||||
* Dice operator is now synced (where possible)
|
||||
* Modulus (%) operator now works on decimal numbers
|
||||
|
|
|
@ -248,8 +248,8 @@ suffix=men|drum|tor|num|lad|de|ak|lol|dum|tam|nur|dium|deum|bil|rook|relm|dium|n
|
|||
#enddef
|
||||
|
||||
#define VILLAGE_NAMES
|
||||
male_names= _ "Bal,Cam,Corn,Del,Earl,El,Fox,Fren,Gel,Hel,Hex,Hol,Hox,Il,Kin,Nam,Nes,New,Ol,Old,Olf,Oul,Ox,Rock,Rook,Sal,Sam,Sed,Sel,Sen,Sil,Tal,Water,Wet,York"
|
||||
name_generator= _ <<
|
||||
base_names= _ "Bal,Cam,Corn,Del,Earl,El,Fox,Fren,Gel,Hel,Hex,Hol,Hox,Il,Kin,Nam,Nes,New,Ol,Old,Olf,Oul,Ox,Rock,Rook,Sal,Sam,Sed,Sel,Sen,Sil,Tal,Water,Wet,York"
|
||||
base_name_generator= _ <<
|
||||
main={prefix}{middle}{suffix}
|
||||
prefix=B|C|D|E|F|Fr|Wat|G|H|K|N|O|R|S|T|W|Y|Ro
|
||||
middle=a|e|o|u|i
|
||||
|
|
|
@ -19,26 +19,6 @@ Night: +25% Damage"
|
|||
Day: −25% Damage
|
||||
Night: −25% Damage"
|
||||
|
||||
#naming of terrain features
|
||||
bridge_name= _ "$name|’s Bridge,$name|’s Crossing"
|
||||
road_name= _ "$name|’s Highway,$name|’s Pass,Path of $name"
|
||||
river_name= _ "$name River,River $name"
|
||||
forest_name= _ "$name Forest,$name|’s Forest"
|
||||
lake_name= _ "$name Lake"
|
||||
mountain_name= _ "$name|’s Peak,Mount $name"
|
||||
swamp_name= _ "$name|’s Swamp,$name|marsh,$name|fen"
|
||||
village_name= _ "$name|bury,$name|ham,$name|ton,$name|bury"
|
||||
village_name_lake= _ "$name|harbor,$name|port,$lake|port,$lake|harbor"
|
||||
village_name_river= _ "$name|ham,$name|ford,$name|cross,$river|ford,$river|cross,$name on river"
|
||||
village_name_river_bridge= _ "$river|bridge,$river|bridge,$river|bridge,$name|ham,$name|bridge,$bridge|ham,$bridge|ton"
|
||||
village_name_grassland= _ "$name|ham,$name|ton,$name|field"
|
||||
village_name_forest= _ "$name|ham,$name|ton,$name|wood,$name Forest,$forest|wood,$forest|ham,$forest|ton"
|
||||
village_name_hill= _ "$name|ham,$name|bury,$name|ton,$name|hill,$name|crest"
|
||||
village_name_mountain= _ "$mountain|mont,$mountain|cliff,$mountain|bury,$mountain|ham"
|
||||
village_name_mountain_anonymous= _ "$name|ham,$name|bury,$name|ton,$name|mont,$name|mont,$name|cliff,$name|cliff"
|
||||
village_name_road= _ "$road|’s Rest,$road|’s Waypoint,$road|bury,$road|ham,$name|bury,$name|ham"
|
||||
village_name_swamp= _ "$name|bury,$name|ham,$name|ton,$swamp|bury,$swamp|ham,$swamp|ton,"
|
||||
|
||||
#ranges
|
||||
range_melee= _ "melee"
|
||||
range_ranged= _ "ranged"
|
||||
|
@ -51,3 +31,28 @@ Night: −25% Damage"
|
|||
type_cold= _ "cold"
|
||||
type_arcane= _ "arcane"
|
||||
[/language]
|
||||
|
||||
#default naming of terrain features
|
||||
[naming]
|
||||
bridge_name_generator= _ << main=$base{!}’s Bridge|$base{!}’s Crossing >>
|
||||
road_name_generator= _ << main=$base{!}’s Highway|$base{!}’s Pass|Path of $base >>
|
||||
river_name_generator= _ << main=$base River|River $base >>
|
||||
forest_name_generator= _ << main=$base Forest|$base{!}’s Forest >>
|
||||
lake_name_generator= _ << main=$base{!} Lake >>
|
||||
mountain_name_generator= _ << main=$base{!}’s Peak|Mount $base >>
|
||||
swamp_name_generator= _ << main=$base{!}’s Swamp|base{!}marsh|$base{!}fen >>
|
||||
[/naming]
|
||||
|
||||
[village_naming]
|
||||
name_generator= _ << main = $base{!}bury|$base{!}ham|$base{!}ton|$base{!}bury >>
|
||||
lake_name_generator= _ << main=$base{!}harbor|$base{!}port|$lake{!}port|$lake{!}harbor >>
|
||||
river_name_generator= _ << main=$base{!}ham|$base{!}ford|$base{!}cross|$river{!}ford|$river{!}cross|$base on $river >>
|
||||
bridge_name_generator= _ << main=$river{!}bridge|$river{!}bridge|$river{!}bridge|$base{!}ham|$base{!}bridge|$bridge{!}ham|$bridge{!}ton >>
|
||||
grassland_name_generator= _ << main=$base{!}ham|$base{!}ton|$base{!}field >>
|
||||
forest_name_generator= _ << main=$base{!}ham|$base{!}ton|$base{!}wood|$base Forest|$forest{!}wood|$forest{!}ham|$forest{!}ton >>
|
||||
hill_name_generator= _ << main=$base{!}ham|$base{!}bury|$base{!}ton|$base{!}hill|$base{!}crest >>
|
||||
mountain_name_generator= _ << main=$mountain{!}mont|$mountain{!}cliff|$mountain{!}bury|$mountain{!}ham >>
|
||||
mountain_anonymous_name_generator= _ << "main=$base{!}ham|$base{!}bury|$base{!}ton|$base{!}mont|$base{!}mont|$base{!}cliff|$base{!}cliff >>
|
||||
road_name_generator= _ << main=$road{!}’s Rest|$road{!}’s Waypoint|$road{!}bury|$road{!}ham|$base{!}bury|$base{!}ham >>
|
||||
swamp_name_generator= _ << main=$base{!}bury|$base{!}ham|$base}ton|$swamp{!}bury|$swamp{!}ham|$swamp{!}ton >>
|
||||
[/village_naming]
|
|
@ -986,6 +986,7 @@ set(wesnoth-main_SRC
|
|||
utils/sha1.cpp
|
||||
utils/context_free_grammar_generator.cpp
|
||||
utils/markov_generator.cpp
|
||||
utils/name_generator_factory.cpp
|
||||
variable.cpp
|
||||
variable_info.cpp
|
||||
whiteboard/action.cpp
|
||||
|
|
|
@ -558,6 +558,7 @@ wesnoth_sources = Split("""
|
|||
utils/sha1.cpp
|
||||
utils/context_free_grammar_generator.cpp
|
||||
utils/markov_generator.cpp
|
||||
utils/name_generator_factory.cpp
|
||||
variable_info.cpp
|
||||
variable.cpp
|
||||
whiteboard/action.cpp
|
||||
|
|
|
@ -27,21 +27,22 @@ static bool two_dots(char a, char b) { return a == '.' && b == '.'; }
|
|||
|
||||
namespace utils {
|
||||
|
||||
template <typename T>
|
||||
class string_map_variable_set : public variable_set
|
||||
{
|
||||
public:
|
||||
string_map_variable_set(const string_map& map) : map_(map) {}
|
||||
string_map_variable_set(const std::map<std::string,T>& map) : map_(map) {}
|
||||
|
||||
virtual config::attribute_value get_variable_const(const std::string &key) const
|
||||
{
|
||||
config::attribute_value val;
|
||||
const string_map::const_iterator itor = map_.find(key);
|
||||
const auto itor = map_.find(key);
|
||||
if (itor != map_.end())
|
||||
val = itor->second;
|
||||
return val;
|
||||
}
|
||||
private:
|
||||
const string_map& map_;
|
||||
const std::map<std::string,T>& map_;
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -213,7 +214,13 @@ namespace utils {
|
|||
|
||||
std::string interpolate_variables_into_string(const std::string &str, const string_map * const symbols)
|
||||
{
|
||||
string_map_variable_set set(*symbols);
|
||||
auto set = string_map_variable_set<t_string>(*symbols);
|
||||
return do_interpolation(str, set);
|
||||
}
|
||||
|
||||
std::string interpolate_variables_into_string(const std::string &str, const std::map<std::string,std::string> * const symbols)
|
||||
{
|
||||
auto set = string_map_variable_set<std::string>(*symbols);
|
||||
return do_interpolation(str, set);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ inline bool might_contain_variables(const std::string &str)
|
|||
* is nullptr, then game event variables will be used instead.
|
||||
*/
|
||||
std::string interpolate_variables_into_string(const std::string &str, const string_map * const symbols);
|
||||
std::string interpolate_variables_into_string(const std::string &str, const std::map<std::string,std::string> * const symbols);
|
||||
std::string interpolate_variables_into_string(const std::string &str, const variable_set& variables);
|
||||
|
||||
/**
|
||||
|
|
|
@ -30,9 +30,9 @@
|
|||
#include "util.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "utils/context_free_grammar_generator.hpp"
|
||||
#include "utils/markov_generator.hpp"
|
||||
#include "utils/name_generator_factory.hpp"
|
||||
#include <SDL.h>
|
||||
#include "game_config_manager.hpp"
|
||||
|
||||
#include "seed_rng.hpp"
|
||||
static lg::log_domain log_mapgen("mapgen");
|
||||
|
@ -40,13 +40,15 @@ static lg::log_domain log_mapgen("mapgen");
|
|||
#define LOG_NG LOG_STREAM(info, log_mapgen)
|
||||
|
||||
default_map_generator_job::default_map_generator_job()
|
||||
: rng_(seed_rng::next_seed())
|
||||
: rng_(seed_rng::next_seed()),
|
||||
game_config_(game_config_manager::get()->game_config())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
default_map_generator_job::default_map_generator_job(uint32_t seed)
|
||||
: rng_(seed)
|
||||
: rng_(seed),
|
||||
game_config_(game_config_manager::get()->game_config())
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -602,35 +604,6 @@ static map_location place_village(const t_translation::t_map& map,
|
|||
return best_loc;
|
||||
}
|
||||
|
||||
std::string default_map_generator_job::generate_name(boost::shared_ptr<name_generator>& name_generator, const std::string& id,
|
||||
std::string* base_name, utils::string_map* additional_symbols)
|
||||
{
|
||||
const std::vector<std::string>& options = utils::split(string_table[id].str());
|
||||
if(options.empty() == false) {
|
||||
const size_t choice = rng_()%options.size();
|
||||
LOG_NG << "calling name generator...\n";
|
||||
const std::string& name = name_generator->generate();
|
||||
LOG_NG << "name generator returned '" << name << "'\n";
|
||||
if(base_name != nullptr) {
|
||||
*base_name = name;
|
||||
}
|
||||
|
||||
LOG_NG << "assigned base name..\n";
|
||||
utils::string_map table;
|
||||
if(additional_symbols == nullptr) {
|
||||
additional_symbols = &table;
|
||||
}
|
||||
|
||||
LOG_NG << "got additional symbols\n";
|
||||
|
||||
(*additional_symbols)["name"] = name;
|
||||
LOG_NG << "interpolation variables into '" << options[choice] << "'\n";
|
||||
return utils::interpolate_variables_into_string(options[choice], additional_symbols);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// "flood fill" a tile name to adjacent tiles of certain terrain
|
||||
static void flood_name(const map_location& start, const std::string& name, std::map<map_location,std::string>& tile_names,
|
||||
const t_translation::t_match& tile_types, const terrain_map& terrain,
|
||||
|
@ -756,6 +729,13 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
// Odd widths are nasty
|
||||
VALIDATE(is_even(width), _("Random maps with an odd width aren't supported."));
|
||||
|
||||
/** Try to find configuration for castles. */
|
||||
const config &castle_config = cfg.child("castle");
|
||||
if (!castle_config) {
|
||||
LOG_NG << "Could not find castle configuration\n";
|
||||
return std::string();
|
||||
}
|
||||
|
||||
int ticks = SDL_GetTicks();
|
||||
|
||||
// Find out what the 'flatland' on this map is, i.e. grassland.
|
||||
|
@ -781,21 +761,45 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
LOG_NG << "done generating height map...\n";
|
||||
LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
|
||||
|
||||
config naming = cfg.child_or_empty("naming");
|
||||
config naming;
|
||||
naming.append_children(game_config_,"naming");
|
||||
if(cfg.has_child("naming"))
|
||||
naming.append_children(cfg,"naming");
|
||||
naming.merge_children("naming");
|
||||
naming = naming.child_or_empty("naming");
|
||||
|
||||
// If the [naming] child is empty, we cannot provide good names.
|
||||
std::map<map_location,std::string>* misc_labels = naming.empty() ? nullptr : labels;
|
||||
|
||||
boost::shared_ptr<name_generator> name_generator;
|
||||
if(naming.has_attribute("name_generator")) {
|
||||
name_generator.reset(new context_free_grammar_generator(naming["name_generator"]));
|
||||
if(!name_generator->is_valid()) {
|
||||
name_generator.reset();
|
||||
std::shared_ptr<name_generator> base_name_generator;
|
||||
std::shared_ptr<name_generator> river_name_generator;
|
||||
std::shared_ptr<name_generator> lake_name_generator;
|
||||
std::shared_ptr<name_generator> road_name_generator;
|
||||
std::shared_ptr<name_generator> bridge_name_generator;
|
||||
std::shared_ptr<name_generator> mountain_name_generator;
|
||||
std::shared_ptr<name_generator> forest_name_generator;
|
||||
std::shared_ptr<name_generator> swamp_name_generator;
|
||||
|
||||
if(misc_labels != nullptr) {
|
||||
|
||||
name_generator_factory base_generator_factory{ naming, {"male", "base", "bridge", "road", "river", "forest", "lake", "mountain", "swamp"} };
|
||||
|
||||
naming.get_old_attribute("base_names", "male_names", "[naming]male_names= is deprecated, use base_names= instead");
|
||||
//Due to the attribute detection feature of the factory we also support male_name_generator= but keep it undocumented.
|
||||
|
||||
if(naming.has_attribute("base_names")) {
|
||||
base_name_generator = base_generator_factory.get_name_generator( (naming.has_attribute("base_names") || naming.has_attribute("base_name_generator")) ? "base" : "male" );
|
||||
}
|
||||
else {
|
||||
base_name_generator = base_generator_factory.get_name_generator("male");
|
||||
}
|
||||
config::attribute_value markov_list = naming.get_old_attribute("names", "male_names",
|
||||
"[naming]male_names is deprecated, use names instead");
|
||||
if(!markov_list.blank()) {
|
||||
name_generator.reset(new markov_generator(utils::split(markov_list), naming["markov_chain_size"], 12));
|
||||
river_name_generator = base_generator_factory.get_name_generator("river");
|
||||
lake_name_generator = base_generator_factory.get_name_generator("lake");
|
||||
road_name_generator = base_generator_factory.get_name_generator("road");
|
||||
bridge_name_generator = base_generator_factory.get_name_generator("bridge");
|
||||
mountain_name_generator = base_generator_factory.get_name_generator("mountain");
|
||||
forest_name_generator = base_generator_factory.get_name_generator("forest");
|
||||
swamp_name_generator = base_generator_factory.get_name_generator("swamp");
|
||||
}
|
||||
|
||||
std::vector<terrain_height_mapper> height_conversion;
|
||||
|
@ -850,9 +854,9 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
terrain, x, y, cfg["river_frequency"]);
|
||||
|
||||
if(river.empty() == false && misc_labels != nullptr) {
|
||||
std::string base_name;
|
||||
std::string base_name = base_name_generator->generate();
|
||||
LOG_NG << "generating name for river...\n";
|
||||
const std::string& name = generate_name(name_generator,"river_name",&base_name);
|
||||
const std::string& name = river_name_generator->generate({{"base", base_name}});
|
||||
LOG_NG << "named river '" << name << "'\n";
|
||||
size_t name_frequency = 20;
|
||||
for(std::vector<location>::const_iterator r = river.begin(); r != river.end(); ++r) {
|
||||
|
@ -875,8 +879,8 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
if(res && misc_labels != nullptr) {
|
||||
bool touches_other_lake = false;
|
||||
|
||||
std::string base_name;
|
||||
const std::string& name = generate_name(name_generator,"lake_name",&base_name);
|
||||
std::string base_name = base_name_generator->generate();
|
||||
const std::string& name = lake_name_generator->generate({{"base", base_name}});
|
||||
|
||||
std::set<location>::const_iterator i;
|
||||
|
||||
|
@ -968,13 +972,6 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
|
||||
LOG_NG << "placing castles...\n";
|
||||
|
||||
/** Try to find configuration for castles. */
|
||||
const config &castle_config = cfg.child("castle");
|
||||
if (!castle_config) {
|
||||
LOG_NG << "Could not find castle configuration\n";
|
||||
return std::string();
|
||||
}
|
||||
|
||||
/*
|
||||
* Castle configuration tag contains a 'valid_terrain' attribute which is a
|
||||
* list of terrains that the castle may appear on.
|
||||
|
@ -1089,8 +1086,8 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
// Search a path out for the road
|
||||
pathfind::plain_route rt = pathfind::a_star_search(src, dst, 10000.0, &calc, width, height);
|
||||
|
||||
std::string road_base_name;
|
||||
const std::string& name = generate_name(name_generator, "road_name", &road_base_name);
|
||||
std::string road_name = base_name_generator->generate();
|
||||
const std::string& name = road_name_generator->generate({{"base", road_name}});
|
||||
const int name_frequency = 20;
|
||||
int name_count = 0;
|
||||
|
||||
|
@ -1154,8 +1151,8 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
|
||||
if(misc_labels != nullptr && on_bridge == false) {
|
||||
on_bridge = true;
|
||||
std::string bridge_base_name;
|
||||
const std::string& name = generate_name(name_generator, "bridge_name", &bridge_base_name);
|
||||
std::string bridge_base_name = base_name_generator->generate();
|
||||
const std::string& name = bridge_name_generator->generate({{"base", bridge_base_name}});
|
||||
const location loc(x - width / 3, y-height/3);
|
||||
misc_labels->insert(std::pair<map_location,std::string>(loc,name));
|
||||
bridge_names.insert(std::pair<location,std::string>(loc, bridge_base_name)); //add to use for village naming
|
||||
|
@ -1186,7 +1183,7 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
|
||||
terrain[x][y] = letter;
|
||||
const location loc(x - width / 3, y - height / 3); //add to use for village naming
|
||||
road_names.insert(std::pair<location,std::string>(loc, road_base_name));
|
||||
road_names.insert(std::pair<location,std::string>(loc, road_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1248,7 +1245,8 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
//name every 15th mountain
|
||||
if ((rng_()%15) == 0) {
|
||||
for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
|
||||
name = generate_name(name_generator, "mountain_name", &base_name);
|
||||
base_name = base_name_generator->generate();
|
||||
name = mountain_name_generator->generate({{"base", base_name}});
|
||||
}
|
||||
misc_labels->insert(std::pair<map_location, std::string>(loc, name));
|
||||
mountain_names.insert(std::pair<location, std::string>(loc, base_name));
|
||||
|
@ -1259,7 +1257,8 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
const std::map<location, std::string>::const_iterator forest_name = forest_names.find(loc);
|
||||
if(forest_name == forest_names.end()) {
|
||||
for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
|
||||
name = generate_name(name_generator, "forest_name", &base_name);
|
||||
base_name = base_name_generator->generate();
|
||||
name = forest_name_generator->generate({{"base", base_name}});
|
||||
}
|
||||
forest_names.insert(std::pair<location, std::string>(loc, base_name));
|
||||
// name all connected forest tiles accordingly
|
||||
|
@ -1271,7 +1270,8 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
const std::map<location, std::string>::const_iterator swamp_name = swamp_names.find(loc);
|
||||
if(swamp_name == swamp_names.end()) {
|
||||
for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
|
||||
name = generate_name(name_generator, "swamp_name", &base_name);
|
||||
base_name = base_name_generator->generate();
|
||||
name = swamp_name_generator->generate({{"base", base_name}});
|
||||
}
|
||||
swamp_names.insert(std::pair<location, std::string>(loc, base_name));
|
||||
// name all connected swamp tiles accordingly
|
||||
|
@ -1284,24 +1284,6 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
|
||||
if (nvillages > 0)
|
||||
{
|
||||
config naming_cfg = cfg.child_or_empty("village_naming");
|
||||
// If the [village_naming] child is empty, we cannot provide good names.
|
||||
std::map<map_location,std::string>* village_labels = naming_cfg.empty() ? nullptr : labels;
|
||||
|
||||
// Specify "class" here because we also have a local variable with the same name
|
||||
boost::shared_ptr<class name_generator> village_names_generator;
|
||||
if(naming_cfg.has_attribute("name_generator")) {
|
||||
village_names_generator.reset(new context_free_grammar_generator(naming["name_generator"]));
|
||||
if(!village_names_generator->is_valid()) {
|
||||
village_names_generator.reset();
|
||||
}
|
||||
}
|
||||
config::attribute_value markov_list = naming_cfg.get_old_attribute("names", "male_names",
|
||||
"[village_naming]male_names is deprecated, use names instead");
|
||||
if(!markov_list.blank()) {
|
||||
village_names_generator.reset(new markov_generator(utils::split(markov_list), naming["markov_chain_size"], 12));
|
||||
}
|
||||
|
||||
// First we work out the size of the x and y distance between villages
|
||||
const size_t tiles_per_village = ((width*height)/9)/nvillages;
|
||||
size_t village_x = 1, village_y = 1;
|
||||
|
@ -1320,6 +1302,16 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
std::set<std::string> used_names;
|
||||
tcode_list_cache adj_liked_cache;
|
||||
|
||||
config village_naming;
|
||||
village_naming.append_children(game_config_,"village_naming");
|
||||
if(cfg.has_child("village_naming"))
|
||||
village_naming.append_children(cfg,"village_naming");
|
||||
village_naming.merge_children("village_naming");
|
||||
village_naming = village_naming.child_or_empty("village_naming");
|
||||
|
||||
// If the [village_naming] child is empty, we cannot provide good names.
|
||||
std::map<map_location,std::string>* village_labels = village_naming.empty() ? nullptr : labels;
|
||||
|
||||
for(size_t vx = 0; vx < width; vx += village_x) {
|
||||
LOG_NG << "village at " << vx << "\n";
|
||||
for(size_t vy = rng_()%village_y; vy < height; vy += village_y) {
|
||||
|
@ -1348,12 +1340,20 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
villages.insert(res);
|
||||
|
||||
if ( village_labels != nullptr ) {
|
||||
|
||||
name_generator_factory village_name_generator_factory{ village_naming, {"base", "male", "village", "lake", "river", "bridge", "grassland", "forest", "hill", "mountain", "mountain_anonymous", "road", "swamp"} };
|
||||
|
||||
village_naming.get_old_attribute("base_names", "male_names", "[village_naming]male_names= is deprecated, use base_names= instead");
|
||||
//Due to the attribute detection feature of the factory we also support male_name_generator= but keep it undocumented.
|
||||
|
||||
base_name_generator = village_name_generator_factory.get_name_generator( (village_naming.has_attribute("base_names") || village_naming.has_attribute("base_name_generator")) ? "base" : "male" );
|
||||
|
||||
const map_location loc(res.x-width/3,res.y-height/3);
|
||||
|
||||
map_location adj[6];
|
||||
get_adjacent_tiles(loc,adj);
|
||||
|
||||
std::string name_type = "village_name";
|
||||
std::string name_type = "village";
|
||||
const t_translation::t_list
|
||||
field = t_translation::t_list(1, t_translation::GRASS_LAND),
|
||||
forest = t_translation::t_list(1, t_translation::FOREST),
|
||||
|
@ -1362,27 +1362,27 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
|
||||
size_t field_count = 0, forest_count = 0, mountain_count = 0, hill_count = 0;
|
||||
|
||||
utils::string_map symbols;
|
||||
std::map<std::string,std::string> symbols;
|
||||
|
||||
size_t n;
|
||||
for(n = 0; n != 6; ++n) {
|
||||
const std::map<location,std::string>::const_iterator road_name = road_names.find(adj[n]);
|
||||
if(road_name != road_names.end()) {
|
||||
symbols["road"] = road_name->second;
|
||||
name_type = "village_name_road";
|
||||
name_type = "road";
|
||||
break;
|
||||
}
|
||||
|
||||
const std::map<location,std::string>::const_iterator river_name = river_names.find(adj[n]);
|
||||
if(river_name != river_names.end()) {
|
||||
symbols["river"] = river_name->second;
|
||||
name_type = "village_name_river";
|
||||
name_type = "river";
|
||||
|
||||
const std::map<location,std::string>::const_iterator bridge_name = bridge_names.find(adj[n]);
|
||||
if(bridge_name != bridge_names.end()) {
|
||||
//we should always end up here, since if there is an adjacent bridge, there has to be an adjacent river too
|
||||
symbols["bridge"] = bridge_name->second;
|
||||
name_type = "village_name_river_bridge";
|
||||
name_type = "river_bridge";
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1391,28 +1391,28 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
const std::map<location,std::string>::const_iterator forest_name = forest_names.find(adj[n]);
|
||||
if(forest_name != forest_names.end()) {
|
||||
symbols["forest"] = forest_name->second;
|
||||
name_type = "village_name_forest";
|
||||
name_type = "forest";
|
||||
break;
|
||||
}
|
||||
|
||||
const std::map<location,std::string>::const_iterator lake_name = lake_names.find(adj[n]);
|
||||
if(lake_name != lake_names.end()) {
|
||||
symbols["lake"] = lake_name->second;
|
||||
name_type = "village_name_lake";
|
||||
name_type = "lake";
|
||||
break;
|
||||
}
|
||||
|
||||
const std::map<location,std::string>::const_iterator mountain_name = mountain_names.find(adj[n]);
|
||||
if(mountain_name != mountain_names.end()) {
|
||||
symbols["mountain"] = mountain_name->second;
|
||||
name_type = "village_name_mountain";
|
||||
name_type = "mountain";
|
||||
break;
|
||||
}
|
||||
|
||||
const std::map<location,std::string>::const_iterator swamp_name = swamp_names.find(adj[n]);
|
||||
if(swamp_name != swamp_names.end()) {
|
||||
symbols["swamp"] = swamp_name->second;
|
||||
name_type = "village_name_swamp";
|
||||
name_type = "swamp";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1432,19 +1432,23 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
|
||||
if(n == 6) {
|
||||
if(field_count == 6) {
|
||||
name_type = "village_name_grassland";
|
||||
name_type = "grassland";
|
||||
} else if(forest_count >= 2) {
|
||||
name_type = "village_name_forest";
|
||||
name_type = "forest";
|
||||
} else if(mountain_count >= 1) {
|
||||
name_type = "village_name_mountain_anonymous";
|
||||
name_type = "name_mountain_anonymous";
|
||||
} else if(hill_count >= 2) {
|
||||
name_type = "village_name_hill";
|
||||
name_type = "hill";
|
||||
}
|
||||
}
|
||||
|
||||
std::string name;
|
||||
|
||||
symbols["base"] = base_name_generator->generate();
|
||||
std::shared_ptr<name_generator> village_name_generator = village_name_generator_factory.get_name_generator(name_type);
|
||||
|
||||
for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
|
||||
name = generate_name(village_names_generator,name_type,nullptr,&symbols);
|
||||
name = village_name_generator->generate( symbols );
|
||||
}
|
||||
|
||||
used_names.insert(name);
|
||||
|
|
|
@ -28,8 +28,8 @@ class unit_race;
|
|||
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
class default_map_generator_job
|
||||
{
|
||||
|
@ -44,7 +44,6 @@ public:
|
|||
bool roads_between_castles, std::map<map_location,std::string>* labels,
|
||||
const config& cfg);
|
||||
private:
|
||||
|
||||
typedef std::vector<std::vector<int> > height_map;
|
||||
typedef t_translation::t_map terrain_map;
|
||||
|
||||
|
@ -60,11 +59,9 @@ private:
|
|||
|
||||
bool generate_lake(t_translation::t_map& terrain, int x, int y, int lake_fall_off, std::set<map_location>& locs_touched);
|
||||
map_location random_point_at_side(size_t width, size_t height);
|
||||
std::string generate_name(boost::shared_ptr<name_generator>& name_generator, const std::string& id,
|
||||
std::string* base_name=nullptr,
|
||||
utils::string_map* additional_symbols=nullptr);
|
||||
|
||||
boost::random::mt19937 rng_;
|
||||
const config& game_config_;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -104,6 +104,7 @@
|
|||
#include "units/ptr.hpp" // for unit_const_ptr, unit_ptr
|
||||
#include "units/types.hpp" // for unit_type_data, unit_types, etc
|
||||
#include "util.hpp" // for lexical_cast
|
||||
#include "utils/name_generator.hpp"
|
||||
#include "utils/markov_generator.hpp"
|
||||
#include "utils/context_free_grammar_generator.hpp"
|
||||
#include "variable.hpp" // for vconfig, etc
|
||||
|
@ -4374,6 +4375,7 @@ static int intf_name_generator(lua_State *L)
|
|||
{
|
||||
std::string type = luaL_checkstring(L, 1);
|
||||
name_generator* gen = nullptr;
|
||||
try {
|
||||
if(type == "markov" || type == "markov_chain") {
|
||||
std::vector<std::string> input;
|
||||
if(lua_istable(L, 2)) {
|
||||
|
@ -4417,19 +4419,17 @@ static int intf_name_generator(lua_State *L)
|
|||
} else {
|
||||
return luaL_argerror(L, 1, "should be either 'markov_chain' or 'context_free'");
|
||||
}
|
||||
static const char*const generic_err = "error initializing name generator";
|
||||
if(!gen) {
|
||||
lua_pushstring(L, generic_err);
|
||||
}
|
||||
catch (const name_generator_invalid_exception& ex) {
|
||||
lua_pushstring(L, ex.what());
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
// We set the metatable now, even if the generator is invalid, so that it
|
||||
// will be properly collected if it was invalid.
|
||||
luaL_getmetatable(L, "name generator");
|
||||
lua_setmetatable(L, -2);
|
||||
if(!gen->is_valid()) {
|
||||
lua_pushstring(L, generic_err);
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,8 +24,8 @@
|
|||
#include "log.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "serialization/unicode_cast.hpp"
|
||||
#include "utils/markov_generator.hpp"
|
||||
#include "utils/context_free_grammar_generator.hpp"
|
||||
#include "utils/name_generator.hpp"
|
||||
#include "utils/name_generator_factory.hpp"
|
||||
|
||||
/// Dummy race used when a race is not yet known.
|
||||
const unit_race unit_race::null_race;
|
||||
|
@ -79,6 +79,7 @@ unit_race::unit_race(const config& cfg) :
|
|||
lg::wml_error() << "[race] '" << cfg["name"] << "' is missing a plural_name field.";
|
||||
plural_name_ = (cfg["name"]);
|
||||
}
|
||||
|
||||
// use "name" if "male_name" or "female_name" aren't available
|
||||
name_[MALE] = cfg["male_name"];
|
||||
if(name_[MALE].empty()) {
|
||||
|
@ -89,34 +90,11 @@ unit_race::unit_race(const config& cfg) :
|
|||
name_[FEMALE] = (cfg["name"]);
|
||||
}
|
||||
|
||||
config::attribute_value male_generator = cfg["male_name_generator"];
|
||||
config::attribute_value female_generator = cfg["female_name_generator"];
|
||||
if(male_generator.blank()) {
|
||||
male_generator = cfg["name_generator"];
|
||||
}
|
||||
if(female_generator.blank()) {
|
||||
female_generator = cfg["name_generator"];
|
||||
}
|
||||
name_generator_factory generator_factory = name_generator_factory(cfg, {"male", "female"});
|
||||
|
||||
if(!male_generator.blank()) {
|
||||
name_generator_[MALE].reset(new context_free_grammar_generator(male_generator));
|
||||
if(!name_generator_[MALE]->is_valid()) {
|
||||
name_generator_[MALE].reset();
|
||||
}
|
||||
}
|
||||
if(!female_generator.blank()) {
|
||||
name_generator_[FEMALE].reset(new context_free_grammar_generator(female_generator));
|
||||
if(!name_generator_[FEMALE]->is_valid()) {
|
||||
name_generator_[FEMALE].reset();
|
||||
}
|
||||
}
|
||||
|
||||
int chain_size = cfg["markov_chain_size"].to_int(2);
|
||||
if(!name_generator_[MALE]) {
|
||||
name_generator_[MALE].reset(new markov_generator(utils::split(cfg["male_names"]), chain_size, 12));
|
||||
}
|
||||
if(!name_generator_[FEMALE]) {
|
||||
name_generator_[FEMALE].reset(new markov_generator(utils::split(cfg["female_names"]), chain_size, 12));
|
||||
for(int i=MALE; i<NUM_GENDERS; i++) {
|
||||
GENDER gender = static_cast<GENDER>(i);
|
||||
name_generator_[i] = generator_factory.get_name_generator(gender_string(gender));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "config.hpp"
|
||||
#include "utils/name_generator.hpp"
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <memory>
|
||||
|
||||
class unit_race
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ private:
|
|||
t_string plural_name_;
|
||||
t_string description_;
|
||||
unsigned int ntraits_;
|
||||
boost::shared_ptr<name_generator> name_generator_[NUM_GENDERS];
|
||||
std::shared_ptr<name_generator> name_generator_[NUM_GENDERS];
|
||||
|
||||
config::const_child_itors traits_;
|
||||
config::const_child_itors topics_;
|
||||
|
|
|
@ -30,8 +30,7 @@ context_free_grammar_generator::~context_free_grammar_generator()
|
|||
{
|
||||
}
|
||||
|
||||
context_free_grammar_generator::context_free_grammar_generator(const std::string& source) :
|
||||
initialized_(false)
|
||||
context_free_grammar_generator::context_free_grammar_generator(const std::string& source)
|
||||
{
|
||||
const char* reading = source.c_str();
|
||||
nonterminal* current = nullptr;
|
||||
|
@ -41,7 +40,11 @@ context_free_grammar_generator::context_free_grammar_generator(const std::string
|
|||
while (*reading != 0) {
|
||||
if (*reading == '=') {
|
||||
// Leading and trailing whitespace is not significant, but internal whitespace is
|
||||
current = &nonterminals_[utils::strip(buf)];
|
||||
std::string key = utils::strip(buf);
|
||||
if(key == "!" || key =="(" || key == ")") {
|
||||
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: nonterminals (, ! and ) may not be overridden");
|
||||
}
|
||||
current = &nonterminals_[key];
|
||||
current->possibilities_.push_back(std::vector<std::string>());
|
||||
filled = ¤t->possibilities_.back();
|
||||
buf.clear();
|
||||
|
@ -53,8 +56,7 @@ context_free_grammar_generator::context_free_grammar_generator(const std::string
|
|||
buf.clear();
|
||||
} else if (*reading == '|') {
|
||||
if (!filled || !current) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced | symbol";
|
||||
return;
|
||||
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced | symbol");
|
||||
}
|
||||
filled->push_back(buf);
|
||||
current->possibilities_.push_back(std::vector<std::string>());
|
||||
|
@ -69,16 +71,14 @@ context_free_grammar_generator::context_free_grammar_generator(const std::string
|
|||
} else {
|
||||
if (*reading == '{') {
|
||||
if (!filled) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced { symbol";
|
||||
return;
|
||||
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced { symbol");
|
||||
}
|
||||
filled->push_back(buf);
|
||||
buf.clear();
|
||||
}
|
||||
else if (*reading == '}') {
|
||||
if (!filled) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced } symbol";
|
||||
return;
|
||||
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced } symbol");
|
||||
}
|
||||
filled->push_back('{' + utils::strip(buf));
|
||||
buf.clear();
|
||||
|
@ -87,16 +87,16 @@ context_free_grammar_generator::context_free_grammar_generator(const std::string
|
|||
reading++;
|
||||
}
|
||||
if (filled) filled->push_back(buf);
|
||||
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
context_free_grammar_generator::context_free_grammar_generator(const std::map<std::string, std::vector<std::string>>& source) :
|
||||
initialized_(false)
|
||||
context_free_grammar_generator::context_free_grammar_generator(const std::map<std::string, std::vector<std::string>>& source)
|
||||
{
|
||||
for(auto rule : source) {
|
||||
std::string key = rule.first; // Need to do this because utils::strip is mutating
|
||||
key = utils::strip(key);
|
||||
if(key == "!" || key =="(" || key == ")") {
|
||||
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: nonterminals (, ! and ) may not be overridden");
|
||||
}
|
||||
std::string buf;
|
||||
for(std::string str : rule.second) {
|
||||
nonterminals_[key].possibilities_.emplace_back();
|
||||
|
@ -105,17 +105,16 @@ context_free_grammar_generator::context_free_grammar_generator(const std::map<st
|
|||
for(char c : str) {
|
||||
if (c == '{') {
|
||||
if (!filled) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced { symbol";
|
||||
return;
|
||||
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced { symbol");
|
||||
}
|
||||
filled->push_back(buf);
|
||||
buf.clear();
|
||||
}
|
||||
else if (c == '}') {
|
||||
if (!filled) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced } symbol";
|
||||
return;
|
||||
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced } symbol");
|
||||
}
|
||||
|
||||
filled->push_back('{' + utils::strip(buf));
|
||||
buf.clear();
|
||||
} else buf.push_back(c);
|
||||
|
@ -125,14 +124,24 @@ context_free_grammar_generator::context_free_grammar_generator(const std::map<st
|
|||
}
|
||||
}
|
||||
}
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
std::string context_free_grammar_generator::print_nonterminal(const std::string& name, uint32_t* seed, short seed_pos) const {
|
||||
std::string result;
|
||||
std::map<std::string, nonterminal>::const_iterator found = nonterminals_.find(name);
|
||||
if (name == "!") {
|
||||
return "|";
|
||||
}
|
||||
else if (name == "(" ) {
|
||||
return "{";
|
||||
}
|
||||
else if (name == ")" ) {
|
||||
return "}";
|
||||
}
|
||||
else {
|
||||
std::string result = "";
|
||||
|
||||
std::map<std::string,nonterminal>::const_iterator found = nonterminals_.find(name);
|
||||
if (found == nonterminals_.end()) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Warning: needed nonterminal " << name << " not defined";
|
||||
lg::wml_error() << "[context_free_grammar_generator] Warning: needed nonterminal" << name << " not defined";
|
||||
return "!" + name;
|
||||
}
|
||||
const context_free_grammar_generator::nonterminal& got = found->second;
|
||||
|
@ -149,12 +158,17 @@ std::string context_free_grammar_generator::print_nonterminal(const std::string&
|
|||
else result += used[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
std::string context_free_grammar_generator::generate() const {
|
||||
uint32_t seed[seed_size];
|
||||
init_seed(seed);
|
||||
return print_nonterminal("main", seed, 0);
|
||||
}
|
||||
|
||||
void context_free_grammar_generator::init_seed(uint32_t seed[]) const {
|
||||
for (unsigned short int i = 0; i < seed_size; i++) {
|
||||
seed[i] = random_new::generator->next_random();
|
||||
}
|
||||
return print_nonterminal("main", seed, 0);
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
#include "utils/name_generator.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
|
@ -32,9 +30,9 @@ private:
|
|||
mutable unsigned int last_;
|
||||
};
|
||||
|
||||
void init_seed(uint32_t seed[]) const;
|
||||
std::map<std::string, nonterminal> nonterminals_;
|
||||
bool initialized_;
|
||||
std::string print_nonterminal(const std::string& name, uint32_t* seed, short int seed_pos) const;
|
||||
std::string print_nonterminal(const std::string& name, uint32_t seed[], short int seed_pos) const;
|
||||
static const short unsigned int seed_size = 20;
|
||||
|
||||
public:
|
||||
|
@ -54,11 +52,6 @@ public:
|
|||
std::string generate() const override;
|
||||
|
||||
~context_free_grammar_generator();
|
||||
|
||||
/** Checks if the object is initialized
|
||||
* @return if it is initialized
|
||||
*/
|
||||
bool is_valid() const override {return initialized_; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,21 +15,36 @@
|
|||
#ifndef NAME_GENERATOR_HPP_INCLUDED
|
||||
#define NAME_GENERATOR_HPP_INCLUDED
|
||||
|
||||
#include "global.hpp"
|
||||
#include <string>
|
||||
#include "formula/string_utils.hpp"
|
||||
#include <exception>
|
||||
|
||||
typedef std::map< std::string, t_string > string_map;
|
||||
|
||||
class name_generator_invalid_exception : public std::exception {
|
||||
public:
|
||||
name_generator_invalid_exception(const char* errMessage):errMessage_(errMessage){}
|
||||
const char* what() const throw() { return errMessage_; }
|
||||
|
||||
private:
|
||||
const char* errMessage_;
|
||||
};
|
||||
|
||||
|
||||
class name_generator {
|
||||
public:
|
||||
virtual std::string generate() const = 0;
|
||||
virtual bool is_valid() const {return true;}
|
||||
virtual ~name_generator() {}
|
||||
std::string generate(const std::map<std::string,std::string>& variables) const { return utils::interpolate_variables_into_string(generate(), &variables); };
|
||||
virtual std::string generate() const { return ""; };
|
||||
name_generator() {};
|
||||
virtual ~name_generator() {};
|
||||
};
|
||||
|
||||
class proxy_name_generator : public name_generator {
|
||||
const name_generator& base;
|
||||
public:
|
||||
proxy_name_generator(const name_generator& b) : base(b) {}
|
||||
std::string generate() const override {return base.generate();}
|
||||
bool is_valid() const override {return base.is_valid();}
|
||||
std::string generate() const override { return base.generate(); };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
68
src/utils/name_generator_factory.cpp
Normal file
68
src/utils/name_generator_factory.cpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "global.hpp"
|
||||
#include "log.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "utils/name_generator_factory.hpp"
|
||||
#include "utils/name_generator.hpp"
|
||||
#include "utils/context_free_grammar_generator.hpp"
|
||||
#include "utils/markov_generator.hpp"
|
||||
|
||||
name_generator_factory::name_generator_factory(const config& config, std::vector<std::string> ids) : name_generators_() {
|
||||
add_name_generator_from_config(config, "", "");
|
||||
|
||||
for (std::vector<std::string>::iterator it = std::begin(ids); it!=std::end(ids); it++) {
|
||||
std::string id = *it;
|
||||
add_name_generator_from_config(config, id, (id + "_"));
|
||||
}
|
||||
};
|
||||
|
||||
void name_generator_factory::add_name_generator_from_config(const config& config, const std::string id, const std::string prefix) {
|
||||
std::string cfg_name = prefix + "name_generator";
|
||||
std::string markov_name = prefix + "names";
|
||||
|
||||
if(config.has_attribute(cfg_name)) {
|
||||
try {
|
||||
name_generators_[id] = std::shared_ptr<name_generator>(new context_free_grammar_generator(config[cfg_name]));
|
||||
}
|
||||
catch (const name_generator_invalid_exception& ex) { lg::wml_error() << ex.what() << '\n'; }
|
||||
}
|
||||
|
||||
if(config.has_attribute(markov_name)) {
|
||||
config::attribute_value markov_name_list = config[markov_name];
|
||||
|
||||
if(!markov_name_list.blank()) {
|
||||
name_generators_[id] = std::shared_ptr<name_generator>(new markov_generator(utils::split(markov_name_list), config["markov_chain_size"].to_int(2), 12));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<name_generator> name_generator_factory::get_name_generator() {
|
||||
std::map<std::string, std::shared_ptr<name_generator>>::const_iterator it = name_generators_.find("");
|
||||
if(it == name_generators_.end()) {
|
||||
//create a dummy instance, which always returns the empty string
|
||||
return std::shared_ptr<name_generator>(new name_generator( ));
|
||||
}
|
||||
|
||||
return it->second;
|
||||
};
|
||||
|
||||
std::shared_ptr<name_generator> name_generator_factory::get_name_generator(const std::string id) {
|
||||
std::map<std::string, std::shared_ptr<name_generator>>::const_iterator it = name_generators_.find(id);
|
||||
if(it == name_generators_.end()) {
|
||||
return get_name_generator();
|
||||
}
|
||||
|
||||
return it->second;
|
||||
};
|
59
src/utils/name_generator_factory.hpp
Normal file
59
src/utils/name_generator_factory.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
Copyright (C) 2016 by Marius Spix
|
||||
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY.
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef NAME_GENERATOR_FACTORY_HPP_INCLUDED
|
||||
#define NAME_GENERATOR_FACTORY_HPP_INCLUDED
|
||||
|
||||
#include "utils/name_generator.hpp"
|
||||
#include "config.hpp"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
class name_generator_factory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates a new name generator factory
|
||||
* @param config the WML data to be parsed for name generators
|
||||
* @param ids a list of generator ids, e.g. genders or terrain types
|
||||
*/
|
||||
name_generator_factory(const config& config, std::vector<std::string> ids);
|
||||
|
||||
/**
|
||||
* Gets the default name generator
|
||||
* @returns the default name generator
|
||||
*/
|
||||
std::shared_ptr<name_generator> get_name_generator();
|
||||
|
||||
/**
|
||||
* Gets a specific name generator or the default name generator, if the
|
||||
* specific name generator is not found.
|
||||
* @param name generator id, e.g. a gender or a terrain type
|
||||
* @returns a name generator
|
||||
*/
|
||||
std::shared_ptr<name_generator> get_name_generator(const std::string name);
|
||||
|
||||
private:
|
||||
std::map<std::string, std::shared_ptr<name_generator>> name_generators_;
|
||||
|
||||
/**
|
||||
* Determines a name generator from WML data
|
||||
* @param config the WML data to be parsed for name generators
|
||||
* @param the prefix to look for
|
||||
* @returns a name generator or nullptr if not found
|
||||
*/
|
||||
void add_name_generator_from_config(const config& config, const std::string id, const std::string prefix);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue