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.
|
and [deprecated_message] tags now use this.
|
||||||
* New wesnoth.name_generator function builds a name generator and returns
|
* New wesnoth.name_generator function builds a name generator and returns
|
||||||
it as a callable userdata. Both the original Markov chain generator
|
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
|
* WML tables defined in Lua now accept string keys with array values
|
||||||
(where "array" is a table whose keys are all integers). This joins
|
(where "array" is a table whose keys are all integers). This joins
|
||||||
the elements of the array with commas and produces a single string
|
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
|
* pair() function that produces a key-value pair suitable for
|
||||||
passing to tomap() - this also means key-value pairs are now
|
passing to tomap() - this also means key-value pairs are now
|
||||||
serializable (relevant in FormulaAI)
|
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:
|
* Bugfixes:
|
||||||
* Dice operator is now synced (where possible)
|
* Dice operator is now synced (where possible)
|
||||||
* Modulus (%) operator now works on decimal numbers
|
* 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
|
#enddef
|
||||||
|
|
||||||
#define VILLAGE_NAMES
|
#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"
|
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"
|
||||||
name_generator= _ <<
|
base_name_generator= _ <<
|
||||||
main={prefix}{middle}{suffix}
|
main={prefix}{middle}{suffix}
|
||||||
prefix=B|C|D|E|F|Fr|Wat|G|H|K|N|O|R|S|T|W|Y|Ro
|
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
|
middle=a|e|o|u|i
|
||||||
|
|
|
@ -19,26 +19,6 @@ Night: +25% Damage"
|
||||||
Day: −25% Damage
|
Day: −25% Damage
|
||||||
Night: −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
|
#ranges
|
||||||
range_melee= _ "melee"
|
range_melee= _ "melee"
|
||||||
range_ranged= _ "ranged"
|
range_ranged= _ "ranged"
|
||||||
|
@ -51,3 +31,28 @@ Night: −25% Damage"
|
||||||
type_cold= _ "cold"
|
type_cold= _ "cold"
|
||||||
type_arcane= _ "arcane"
|
type_arcane= _ "arcane"
|
||||||
[/language]
|
[/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/sha1.cpp
|
||||||
utils/context_free_grammar_generator.cpp
|
utils/context_free_grammar_generator.cpp
|
||||||
utils/markov_generator.cpp
|
utils/markov_generator.cpp
|
||||||
|
utils/name_generator_factory.cpp
|
||||||
variable.cpp
|
variable.cpp
|
||||||
variable_info.cpp
|
variable_info.cpp
|
||||||
whiteboard/action.cpp
|
whiteboard/action.cpp
|
||||||
|
|
|
@ -558,6 +558,7 @@ wesnoth_sources = Split("""
|
||||||
utils/sha1.cpp
|
utils/sha1.cpp
|
||||||
utils/context_free_grammar_generator.cpp
|
utils/context_free_grammar_generator.cpp
|
||||||
utils/markov_generator.cpp
|
utils/markov_generator.cpp
|
||||||
|
utils/name_generator_factory.cpp
|
||||||
variable_info.cpp
|
variable_info.cpp
|
||||||
variable.cpp
|
variable.cpp
|
||||||
whiteboard/action.cpp
|
whiteboard/action.cpp
|
||||||
|
|
|
@ -27,21 +27,22 @@ static bool two_dots(char a, char b) { return a == '.' && b == '.'; }
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
class string_map_variable_set : public variable_set
|
class string_map_variable_set : public variable_set
|
||||||
{
|
{
|
||||||
public:
|
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
|
virtual config::attribute_value get_variable_const(const std::string &key) const
|
||||||
{
|
{
|
||||||
config::attribute_value val;
|
config::attribute_value val;
|
||||||
const string_map::const_iterator itor = map_.find(key);
|
const auto itor = map_.find(key);
|
||||||
if (itor != map_.end())
|
if (itor != map_.end())
|
||||||
val = itor->second;
|
val = itor->second;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
private:
|
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)
|
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);
|
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.
|
* 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 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);
|
std::string interpolate_variables_into_string(const std::string &str, const variable_set& variables);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -30,9 +30,9 @@
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
#include "wml_exception.hpp"
|
#include "wml_exception.hpp"
|
||||||
#include "formula/string_utils.hpp"
|
#include "formula/string_utils.hpp"
|
||||||
#include "utils/context_free_grammar_generator.hpp"
|
#include "utils/name_generator_factory.hpp"
|
||||||
#include "utils/markov_generator.hpp"
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include "game_config_manager.hpp"
|
||||||
|
|
||||||
#include "seed_rng.hpp"
|
#include "seed_rng.hpp"
|
||||||
static lg::log_domain log_mapgen("mapgen");
|
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)
|
#define LOG_NG LOG_STREAM(info, log_mapgen)
|
||||||
|
|
||||||
default_map_generator_job::default_map_generator_job()
|
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)
|
default_map_generator_job::default_map_generator_job(uint32_t seed)
|
||||||
: rng_(seed)
|
: rng_(seed),
|
||||||
|
game_config_(game_config_manager::get()->game_config())
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -70,7 +72,7 @@ typedef map_location location;
|
||||||
* 0 indicates no island.
|
* 0 indicates no island.
|
||||||
*/
|
*/
|
||||||
height_map default_map_generator_job::generate_height_map(size_t width, size_t height,
|
height_map default_map_generator_job::generate_height_map(size_t width, size_t height,
|
||||||
size_t iterations, size_t hill_size,
|
size_t iterations, size_t hill_size,
|
||||||
size_t island_size, size_t island_off_center)
|
size_t island_size, size_t island_off_center)
|
||||||
{
|
{
|
||||||
height_map res(width, std::vector<int>(height,0));
|
height_map res(width, std::vector<int>(height,0));
|
||||||
|
@ -119,9 +121,9 @@ height_map default_map_generator_job::generate_height_map(size_t width, size_t h
|
||||||
bool is_valley = false;
|
bool is_valley = false;
|
||||||
|
|
||||||
int x1 = island_size > 0 ? center_x - island_size + (rng_()%(island_size*2)) :
|
int x1 = island_size > 0 ? center_x - island_size + (rng_()%(island_size*2)) :
|
||||||
int(rng_()%width);
|
int(rng_()%width);
|
||||||
int y1 = island_size > 0 ? center_y - island_size + (rng_()%(island_size*2)) :
|
int y1 = island_size > 0 ? center_y - island_size + (rng_()%(island_size*2)) :
|
||||||
int(rng_()%height);
|
int(rng_()%height);
|
||||||
|
|
||||||
// We have to check whether this is actually a valley
|
// We have to check whether this is actually a valley
|
||||||
if(island_size != 0) {
|
if(island_size != 0) {
|
||||||
|
@ -273,7 +275,7 @@ bool default_map_generator_job::generate_river_internal(const height_map& height
|
||||||
|
|
||||||
// Generate the river
|
// Generate the river
|
||||||
for(std::vector<location>::const_iterator i = river.begin();
|
for(std::vector<location>::const_iterator i = river.begin();
|
||||||
i != river.end(); ++i) {
|
i != river.end(); ++i) {
|
||||||
terrain[i->x][i->y] = t_translation::SHALLOW_WATER;
|
terrain[i->x][i->y] = t_translation::SHALLOW_WATER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +384,7 @@ namespace {
|
||||||
struct road_path_calculator : pathfind::cost_calculator
|
struct road_path_calculator : pathfind::cost_calculator
|
||||||
{
|
{
|
||||||
road_path_calculator(const terrain_map& terrain, const config& cfg, int seed) :
|
road_path_calculator(const terrain_map& terrain, const config& cfg, int seed) :
|
||||||
calls(0),
|
calls(0),
|
||||||
map_(terrain),
|
map_(terrain),
|
||||||
cfg_(cfg),
|
cfg_(cfg),
|
||||||
// Find out how windy roads should be.
|
// Find out how windy roads should be.
|
||||||
|
@ -521,7 +523,7 @@ static int rank_castle_location(int x, int y, const is_valid_terrain& valid_terr
|
||||||
const int y_from_border = std::min<int>(y - min_y,max_y - y);
|
const int y_from_border = std::min<int>(y - min_y,max_y - y);
|
||||||
|
|
||||||
const int border_ranking = min_distance - std::min<int>(x_from_border,y_from_border) +
|
const int border_ranking = min_distance - std::min<int>(x_from_border,y_from_border) +
|
||||||
min_distance - x_from_border - y_from_border;
|
min_distance - x_from_border - y_from_border;
|
||||||
|
|
||||||
int current_ranking = border_ranking*2 + avg_distance*10 + lowest_distance*10;
|
int current_ranking = border_ranking*2 + avg_distance*10 + lowest_distance*10;
|
||||||
static const int num_nearby_locations = 11*11;
|
static const int num_nearby_locations = 11*11;
|
||||||
|
@ -602,35 +604,6 @@ static map_location place_village(const t_translation::t_map& map,
|
||||||
return best_loc;
|
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
|
// "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,
|
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,
|
const t_translation::t_match& tile_types, const terrain_map& terrain,
|
||||||
|
@ -665,8 +638,8 @@ namespace {
|
||||||
|
|
||||||
// the configuration file should contain a number of [height] tags:
|
// the configuration file should contain a number of [height] tags:
|
||||||
// [height]
|
// [height]
|
||||||
// height=n
|
// height=n
|
||||||
// terrain=x
|
// terrain=x
|
||||||
// [/height]
|
// [/height]
|
||||||
// These should be in descending order of n.
|
// These should be in descending order of n.
|
||||||
// They are checked sequentially, and if height is greater than n for that tile,
|
// They are checked sequentially, and if height is greater than n for that tile,
|
||||||
|
@ -736,7 +709,7 @@ bool terrain_converter::convert_terrain(const t_translation::t_terrain & terrain
|
||||||
const int height, const int temperature) const
|
const int height, const int temperature) const
|
||||||
{
|
{
|
||||||
return std::find(from.begin(),from.end(),terrain) != from.end() && height >= min_height && height <= max_height &&
|
return std::find(from.begin(),from.end(),terrain) != from.end() && height >= min_height && height <= max_height &&
|
||||||
temperature >= min_temp && temperature <= max_temp && to != t_translation::NONE_TERRAIN;
|
temperature >= min_temp && temperature <= max_temp && to != t_translation::NONE_TERRAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
t_translation::t_terrain terrain_converter::convert_to() const
|
t_translation::t_terrain terrain_converter::convert_to() const
|
||||||
|
@ -747,8 +720,8 @@ t_translation::t_terrain terrain_converter::convert_to() const
|
||||||
} // end anon namespace
|
} // end anon namespace
|
||||||
|
|
||||||
std::string default_map_generator_job::default_generate_map(size_t width, size_t height, size_t island_size, size_t island_off_center,
|
std::string default_map_generator_job::default_generate_map(size_t width, size_t height, size_t island_size, size_t island_off_center,
|
||||||
size_t iterations, size_t hill_size,
|
size_t iterations, size_t hill_size,
|
||||||
size_t max_lakes, size_t nvillages, size_t castle_size, size_t nplayers, bool roads_between_castles,
|
size_t max_lakes, size_t nvillages, size_t castle_size, size_t nplayers, bool roads_between_castles,
|
||||||
std::map<map_location,std::string>* labels, const config& cfg)
|
std::map<map_location,std::string>* labels, const config& cfg)
|
||||||
{
|
{
|
||||||
log_scope("map generation");
|
log_scope("map generation");
|
||||||
|
@ -756,6 +729,13 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
||||||
// Odd widths are nasty
|
// Odd widths are nasty
|
||||||
VALIDATE(is_even(width), _("Random maps with an odd width aren't supported."));
|
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();
|
int ticks = SDL_GetTicks();
|
||||||
|
|
||||||
// Find out what the 'flatland' on this map is, i.e. grassland.
|
// 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 << "done generating height map...\n";
|
||||||
LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();
|
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.
|
// If the [naming] child is empty, we cannot provide good names.
|
||||||
std::map<map_location,std::string>* misc_labels = naming.empty() ? nullptr : labels;
|
std::map<map_location,std::string>* misc_labels = naming.empty() ? nullptr : labels;
|
||||||
|
|
||||||
boost::shared_ptr<name_generator> name_generator;
|
std::shared_ptr<name_generator> base_name_generator;
|
||||||
if(naming.has_attribute("name_generator")) {
|
std::shared_ptr<name_generator> river_name_generator;
|
||||||
name_generator.reset(new context_free_grammar_generator(naming["name_generator"]));
|
std::shared_ptr<name_generator> lake_name_generator;
|
||||||
if(!name_generator->is_valid()) {
|
std::shared_ptr<name_generator> road_name_generator;
|
||||||
name_generator.reset();
|
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 {
|
||||||
config::attribute_value markov_list = naming.get_old_attribute("names", "male_names",
|
base_name_generator = base_generator_factory.get_name_generator("male");
|
||||||
"[naming]male_names is deprecated, use names instead");
|
}
|
||||||
if(!markov_list.blank()) {
|
river_name_generator = base_generator_factory.get_name_generator("river");
|
||||||
name_generator.reset(new markov_generator(utils::split(markov_list), naming["markov_chain_size"], 12));
|
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;
|
std::vector<terrain_height_mapper> height_conversion;
|
||||||
|
@ -809,7 +813,7 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
||||||
for(x = 0; x != heights.size(); ++x) {
|
for(x = 0; x != heights.size(); ++x) {
|
||||||
for(y = 0; y != heights[x].size(); ++y) {
|
for(y = 0; y != heights[x].size(); ++y) {
|
||||||
for(std::vector<terrain_height_mapper>::const_iterator i = height_conversion.begin();
|
for(std::vector<terrain_height_mapper>::const_iterator i = height_conversion.begin();
|
||||||
i != height_conversion.end(); ++i) {
|
i != height_conversion.end(); ++i) {
|
||||||
if(i->convert_terrain(heights[x][y])) {
|
if(i->convert_terrain(heights[x][y])) {
|
||||||
terrain[x][y] = i->convert_to();
|
terrain[x][y] = i->convert_to();
|
||||||
break;
|
break;
|
||||||
|
@ -850,9 +854,9 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
||||||
terrain, x, y, cfg["river_frequency"]);
|
terrain, x, y, cfg["river_frequency"]);
|
||||||
|
|
||||||
if(river.empty() == false && misc_labels != nullptr) {
|
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";
|
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";
|
LOG_NG << "named river '" << name << "'\n";
|
||||||
size_t name_frequency = 20;
|
size_t name_frequency = 20;
|
||||||
for(std::vector<location>::const_iterator r = river.begin(); r != river.end(); ++r) {
|
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) {
|
if(res && misc_labels != nullptr) {
|
||||||
bool touches_other_lake = false;
|
bool touches_other_lake = false;
|
||||||
|
|
||||||
std::string base_name;
|
std::string base_name = base_name_generator->generate();
|
||||||
const std::string& name = generate_name(name_generator,"lake_name",&base_name);
|
const std::string& name = lake_name_generator->generate({{"base", base_name}});
|
||||||
|
|
||||||
std::set<location>::const_iterator i;
|
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";
|
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
|
* Castle configuration tag contains a 'valid_terrain' attribute which is a
|
||||||
* list of terrains that the castle may appear on.
|
* 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
|
// Search a path out for the road
|
||||||
pathfind::plain_route rt = pathfind::a_star_search(src, dst, 10000.0, &calc, width, height);
|
pathfind::plain_route rt = pathfind::a_star_search(src, dst, 10000.0, &calc, width, height);
|
||||||
|
|
||||||
std::string road_base_name;
|
std::string road_name = base_name_generator->generate();
|
||||||
const std::string& name = generate_name(name_generator, "road_name", &road_base_name);
|
const std::string& name = road_name_generator->generate({{"base", road_name}});
|
||||||
const int name_frequency = 20;
|
const int name_frequency = 20;
|
||||||
int name_count = 0;
|
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) {
|
if(misc_labels != nullptr && on_bridge == false) {
|
||||||
on_bridge = true;
|
on_bridge = true;
|
||||||
std::string bridge_base_name;
|
std::string bridge_base_name = base_name_generator->generate();
|
||||||
const std::string& name = generate_name(name_generator, "bridge_name", &bridge_base_name);
|
const std::string& name = bridge_name_generator->generate({{"base", bridge_base_name}});
|
||||||
const location loc(x - width / 3, y-height/3);
|
const location loc(x - width / 3, y-height/3);
|
||||||
misc_labels->insert(std::pair<map_location,std::string>(loc,name));
|
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
|
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;
|
terrain[x][y] = letter;
|
||||||
const location loc(x - width / 3, y - height / 3); //add to use for village naming
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1221,7 +1218,7 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
||||||
if(labels != nullptr) {
|
if(labels != nullptr) {
|
||||||
labels->erase(location(x-width/3,y-height/3));
|
labels->erase(location(x-width/3,y-height/3));
|
||||||
for (size_t i = 0; i < castle_size - 1; i++) {
|
for (size_t i = 0; i < castle_size - 1; i++) {
|
||||||
labels->erase(location(x+castles[i][0]-width/3,
|
labels->erase(location(x+castles[i][0]-width/3,
|
||||||
y+castles[i][1]-height/3));
|
y+castles[i][1]-height/3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1248,7 +1245,8 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
||||||
//name every 15th mountain
|
//name every 15th mountain
|
||||||
if ((rng_()%15) == 0) {
|
if ((rng_()%15) == 0) {
|
||||||
for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
|
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));
|
misc_labels->insert(std::pair<map_location, std::string>(loc, name));
|
||||||
mountain_names.insert(std::pair<location, std::string>(loc, base_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);
|
const std::map<location, std::string>::const_iterator forest_name = forest_names.find(loc);
|
||||||
if(forest_name == forest_names.end()) {
|
if(forest_name == forest_names.end()) {
|
||||||
for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
|
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));
|
forest_names.insert(std::pair<location, std::string>(loc, base_name));
|
||||||
// name all connected forest tiles accordingly
|
// 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);
|
const std::map<location, std::string>::const_iterator swamp_name = swamp_names.find(loc);
|
||||||
if(swamp_name == swamp_names.end()) {
|
if(swamp_name == swamp_names.end()) {
|
||||||
for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
|
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));
|
swamp_names.insert(std::pair<location, std::string>(loc, base_name));
|
||||||
// name all connected swamp tiles accordingly
|
// 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)
|
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
|
// First we work out the size of the x and y distance between villages
|
||||||
const size_t tiles_per_village = ((width*height)/9)/nvillages;
|
const size_t tiles_per_village = ((width*height)/9)/nvillages;
|
||||||
size_t village_x = 1, village_y = 1;
|
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;
|
std::set<std::string> used_names;
|
||||||
tcode_list_cache adj_liked_cache;
|
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) {
|
for(size_t vx = 0; vx < width; vx += village_x) {
|
||||||
LOG_NG << "village at " << vx << "\n";
|
LOG_NG << "village at " << vx << "\n";
|
||||||
for(size_t vy = rng_()%village_y; vy < height; vy += village_y) {
|
for(size_t vy = rng_()%village_y; vy < height; vy += village_y) {
|
||||||
|
@ -1348,41 +1340,49 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
||||||
villages.insert(res);
|
villages.insert(res);
|
||||||
|
|
||||||
if ( village_labels != nullptr ) {
|
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);
|
const map_location loc(res.x-width/3,res.y-height/3);
|
||||||
|
|
||||||
map_location adj[6];
|
map_location adj[6];
|
||||||
get_adjacent_tiles(loc,adj);
|
get_adjacent_tiles(loc,adj);
|
||||||
|
|
||||||
std::string name_type = "village_name";
|
std::string name_type = "village";
|
||||||
const t_translation::t_list
|
const t_translation::t_list
|
||||||
field = t_translation::t_list(1, t_translation::GRASS_LAND),
|
field = t_translation::t_list(1, t_translation::GRASS_LAND),
|
||||||
forest = t_translation::t_list(1, t_translation::FOREST),
|
forest = t_translation::t_list(1, t_translation::FOREST),
|
||||||
mountain = t_translation::t_list(1, t_translation::MOUNTAIN),
|
mountain = t_translation::t_list(1, t_translation::MOUNTAIN),
|
||||||
hill = t_translation::t_list(1, t_translation::HILL);
|
hill = t_translation::t_list(1, t_translation::HILL);
|
||||||
|
|
||||||
size_t field_count = 0, forest_count = 0, mountain_count = 0, hill_count = 0;
|
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;
|
size_t n;
|
||||||
for(n = 0; n != 6; ++n) {
|
for(n = 0; n != 6; ++n) {
|
||||||
const std::map<location,std::string>::const_iterator road_name = road_names.find(adj[n]);
|
const std::map<location,std::string>::const_iterator road_name = road_names.find(adj[n]);
|
||||||
if(road_name != road_names.end()) {
|
if(road_name != road_names.end()) {
|
||||||
symbols["road"] = road_name->second;
|
symbols["road"] = road_name->second;
|
||||||
name_type = "village_name_road";
|
name_type = "road";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<location,std::string>::const_iterator river_name = river_names.find(adj[n]);
|
const std::map<location,std::string>::const_iterator river_name = river_names.find(adj[n]);
|
||||||
if(river_name != river_names.end()) {
|
if(river_name != river_names.end()) {
|
||||||
symbols["river"] = river_name->second;
|
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]);
|
const std::map<location,std::string>::const_iterator bridge_name = bridge_names.find(adj[n]);
|
||||||
if(bridge_name != bridge_names.end()) {
|
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
|
//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;
|
symbols["bridge"] = bridge_name->second;
|
||||||
name_type = "village_name_river_bridge";
|
name_type = "river_bridge";
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
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]);
|
const std::map<location,std::string>::const_iterator forest_name = forest_names.find(adj[n]);
|
||||||
if(forest_name != forest_names.end()) {
|
if(forest_name != forest_names.end()) {
|
||||||
symbols["forest"] = forest_name->second;
|
symbols["forest"] = forest_name->second;
|
||||||
name_type = "village_name_forest";
|
name_type = "forest";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<location,std::string>::const_iterator lake_name = lake_names.find(adj[n]);
|
const std::map<location,std::string>::const_iterator lake_name = lake_names.find(adj[n]);
|
||||||
if(lake_name != lake_names.end()) {
|
if(lake_name != lake_names.end()) {
|
||||||
symbols["lake"] = lake_name->second;
|
symbols["lake"] = lake_name->second;
|
||||||
name_type = "village_name_lake";
|
name_type = "lake";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<location,std::string>::const_iterator mountain_name = mountain_names.find(adj[n]);
|
const std::map<location,std::string>::const_iterator mountain_name = mountain_names.find(adj[n]);
|
||||||
if(mountain_name != mountain_names.end()) {
|
if(mountain_name != mountain_names.end()) {
|
||||||
symbols["mountain"] = mountain_name->second;
|
symbols["mountain"] = mountain_name->second;
|
||||||
name_type = "village_name_mountain";
|
name_type = "mountain";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::map<location,std::string>::const_iterator swamp_name = swamp_names.find(adj[n]);
|
const std::map<location,std::string>::const_iterator swamp_name = swamp_names.find(adj[n]);
|
||||||
if(swamp_name != swamp_names.end()) {
|
if(swamp_name != swamp_names.end()) {
|
||||||
symbols["swamp"] = swamp_name->second;
|
symbols["swamp"] = swamp_name->second;
|
||||||
name_type = "village_name_swamp";
|
name_type = "swamp";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1432,19 +1432,23 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
||||||
|
|
||||||
if(n == 6) {
|
if(n == 6) {
|
||||||
if(field_count == 6) {
|
if(field_count == 6) {
|
||||||
name_type = "village_name_grassland";
|
name_type = "grassland";
|
||||||
} else if(forest_count >= 2) {
|
} else if(forest_count >= 2) {
|
||||||
name_type = "village_name_forest";
|
name_type = "forest";
|
||||||
} else if(mountain_count >= 1) {
|
} else if(mountain_count >= 1) {
|
||||||
name_type = "village_name_mountain_anonymous";
|
name_type = "name_mountain_anonymous";
|
||||||
} else if(hill_count >= 2) {
|
} else if(hill_count >= 2) {
|
||||||
name_type = "village_name_hill";
|
name_type = "hill";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name;
|
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) {
|
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);
|
used_names.insert(name);
|
||||||
|
|
|
@ -28,8 +28,8 @@ class unit_race;
|
||||||
|
|
||||||
#include <boost/random.hpp>
|
#include <boost/random.hpp>
|
||||||
#include <boost/cstdint.hpp>
|
#include <boost/cstdint.hpp>
|
||||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class default_map_generator_job
|
class default_map_generator_job
|
||||||
{
|
{
|
||||||
|
@ -44,7 +44,6 @@ public:
|
||||||
bool roads_between_castles, std::map<map_location,std::string>* labels,
|
bool roads_between_castles, std::map<map_location,std::string>* labels,
|
||||||
const config& cfg);
|
const config& cfg);
|
||||||
private:
|
private:
|
||||||
|
|
||||||
typedef std::vector<std::vector<int> > height_map;
|
typedef std::vector<std::vector<int> > height_map;
|
||||||
typedef t_translation::t_map terrain_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);
|
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);
|
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_;
|
boost::random::mt19937 rng_;
|
||||||
|
const config& game_config_;
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -104,6 +104,7 @@
|
||||||
#include "units/ptr.hpp" // for unit_const_ptr, unit_ptr
|
#include "units/ptr.hpp" // for unit_const_ptr, unit_ptr
|
||||||
#include "units/types.hpp" // for unit_type_data, unit_types, etc
|
#include "units/types.hpp" // for unit_type_data, unit_types, etc
|
||||||
#include "util.hpp" // for lexical_cast
|
#include "util.hpp" // for lexical_cast
|
||||||
|
#include "utils/name_generator.hpp"
|
||||||
#include "utils/markov_generator.hpp"
|
#include "utils/markov_generator.hpp"
|
||||||
#include "utils/context_free_grammar_generator.hpp"
|
#include "utils/context_free_grammar_generator.hpp"
|
||||||
#include "variable.hpp" // for vconfig, etc
|
#include "variable.hpp" // for vconfig, etc
|
||||||
|
@ -4374,62 +4375,61 @@ static int intf_name_generator(lua_State *L)
|
||||||
{
|
{
|
||||||
std::string type = luaL_checkstring(L, 1);
|
std::string type = luaL_checkstring(L, 1);
|
||||||
name_generator* gen = nullptr;
|
name_generator* gen = nullptr;
|
||||||
if(type == "markov" || type == "markov_chain") {
|
try {
|
||||||
std::vector<std::string> input;
|
if(type == "markov" || type == "markov_chain") {
|
||||||
if(lua_istable(L, 2)) {
|
std::vector<std::string> input;
|
||||||
input = lua_check<std::vector<std::string>>(L, 2);
|
if(lua_istable(L, 2)) {
|
||||||
} else {
|
input = lua_check<std::vector<std::string>>(L, 2);
|
||||||
input = utils::parenthetical_split(luaL_checkstring(L, 2));
|
} else {
|
||||||
}
|
input = utils::parenthetical_split(luaL_checkstring(L, 2));
|
||||||
int chain_sz = luaL_optinteger(L, 3, 2);
|
|
||||||
int max_len = luaL_optinteger(L, 4, 12);
|
|
||||||
gen = new(lua_newuserdata(L, sizeof(markov_generator)))
|
|
||||||
markov_generator(input, chain_sz, max_len);
|
|
||||||
// Ensure the pointer didn't change when cast
|
|
||||||
assert(static_cast<void*>(gen) == dynamic_cast<markov_generator*>(gen));
|
|
||||||
} else if(type == "context_free" || type == "cfg" || type == "CFG") {
|
|
||||||
void* buf = lua_newuserdata(L, sizeof(context_free_grammar_generator));
|
|
||||||
if(lua_istable(L, 2)) {
|
|
||||||
std::map<std::string, std::vector<std::string>> data;
|
|
||||||
for(lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
|
|
||||||
if(!lua_isstring(L, -2)) {
|
|
||||||
lua_pushstring(L, "CFG generator: invalid nonterminal name (must be a string)");
|
|
||||||
return lua_error(L);
|
|
||||||
}
|
|
||||||
if(lua_isstring(L, -1)) {
|
|
||||||
data[lua_tostring(L,-2)] = utils::split(lua_tostring(L,-1),'|');
|
|
||||||
} else if(lua_istable(L, -1)) {
|
|
||||||
data[lua_tostring(L,-2)] = lua_check<std::vector<std::string>>(L, -1);
|
|
||||||
} else {
|
|
||||||
lua_pushstring(L, "CFG generator: invalid noterminal value (must be a string or list of strings)");
|
|
||||||
return lua_error(L);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(!data.empty()) {
|
int chain_sz = luaL_optinteger(L, 3, 2);
|
||||||
gen = new(buf) context_free_grammar_generator(data);
|
int max_len = luaL_optinteger(L, 4, 12);
|
||||||
|
gen = new(lua_newuserdata(L, sizeof(markov_generator)))
|
||||||
|
markov_generator(input, chain_sz, max_len);
|
||||||
|
// Ensure the pointer didn't change when cast
|
||||||
|
assert(static_cast<void*>(gen) == dynamic_cast<markov_generator*>(gen));
|
||||||
|
} else if(type == "context_free" || type == "cfg" || type == "CFG") {
|
||||||
|
void* buf = lua_newuserdata(L, sizeof(context_free_grammar_generator));
|
||||||
|
if(lua_istable(L, 2)) {
|
||||||
|
std::map<std::string, std::vector<std::string>> data;
|
||||||
|
for(lua_pushnil(L); lua_next(L, 2); lua_pop(L, 1)) {
|
||||||
|
if(!lua_isstring(L, -2)) {
|
||||||
|
lua_pushstring(L, "CFG generator: invalid nonterminal name (must be a string)");
|
||||||
|
return lua_error(L);
|
||||||
|
}
|
||||||
|
if(lua_isstring(L, -1)) {
|
||||||
|
data[lua_tostring(L,-2)] = utils::split(lua_tostring(L,-1),'|');
|
||||||
|
} else if(lua_istable(L, -1)) {
|
||||||
|
data[lua_tostring(L,-2)] = lua_check<std::vector<std::string>>(L, -1);
|
||||||
|
} else {
|
||||||
|
lua_pushstring(L, "CFG generator: invalid noterminal value (must be a string or list of strings)");
|
||||||
|
return lua_error(L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!data.empty()) {
|
||||||
|
gen = new(buf) context_free_grammar_generator(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
gen = new(buf) context_free_grammar_generator(luaL_checkstring(L, 2));
|
||||||
|
}
|
||||||
|
if(gen) {
|
||||||
|
assert(static_cast<void*>(gen) == dynamic_cast<context_free_grammar_generator*>(gen));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gen = new(buf) context_free_grammar_generator(luaL_checkstring(L, 2));
|
return luaL_argerror(L, 1, "should be either 'markov_chain' or 'context_free'");
|
||||||
}
|
}
|
||||||
if(gen) {
|
|
||||||
assert(static_cast<void*>(gen) == dynamic_cast<context_free_grammar_generator*>(gen));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return luaL_argerror(L, 1, "should be either 'markov_chain' or 'context_free'");
|
|
||||||
}
|
}
|
||||||
static const char*const generic_err = "error initializing name generator";
|
catch (const name_generator_invalid_exception& ex) {
|
||||||
if(!gen) {
|
lua_pushstring(L, ex.what());
|
||||||
lua_pushstring(L, generic_err);
|
|
||||||
return lua_error(L);
|
return lua_error(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We set the metatable now, even if the generator is invalid, so that it
|
// We set the metatable now, even if the generator is invalid, so that it
|
||||||
// will be properly collected if it was invalid.
|
// will be properly collected if it was invalid.
|
||||||
luaL_getmetatable(L, "name generator");
|
luaL_getmetatable(L, "name generator");
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
if(!gen->is_valid()) {
|
|
||||||
lua_pushstring(L, generic_err);
|
|
||||||
return lua_error(L);
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
#include "log.hpp"
|
#include "log.hpp"
|
||||||
#include "serialization/string_utils.hpp"
|
#include "serialization/string_utils.hpp"
|
||||||
#include "serialization/unicode_cast.hpp"
|
#include "serialization/unicode_cast.hpp"
|
||||||
#include "utils/markov_generator.hpp"
|
#include "utils/name_generator.hpp"
|
||||||
#include "utils/context_free_grammar_generator.hpp"
|
#include "utils/name_generator_factory.hpp"
|
||||||
|
|
||||||
/// Dummy race used when a race is not yet known.
|
/// Dummy race used when a race is not yet known.
|
||||||
const unit_race unit_race::null_race;
|
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.";
|
lg::wml_error() << "[race] '" << cfg["name"] << "' is missing a plural_name field.";
|
||||||
plural_name_ = (cfg["name"]);
|
plural_name_ = (cfg["name"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// use "name" if "male_name" or "female_name" aren't available
|
// use "name" if "male_name" or "female_name" aren't available
|
||||||
name_[MALE] = cfg["male_name"];
|
name_[MALE] = cfg["male_name"];
|
||||||
if(name_[MALE].empty()) {
|
if(name_[MALE].empty()) {
|
||||||
|
@ -89,34 +90,11 @@ unit_race::unit_race(const config& cfg) :
|
||||||
name_[FEMALE] = (cfg["name"]);
|
name_[FEMALE] = (cfg["name"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
config::attribute_value male_generator = cfg["male_name_generator"];
|
name_generator_factory generator_factory = name_generator_factory(cfg, {"male", "female"});
|
||||||
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"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!male_generator.blank()) {
|
for(int i=MALE; i<NUM_GENDERS; i++) {
|
||||||
name_generator_[MALE].reset(new context_free_grammar_generator(male_generator));
|
GENDER gender = static_cast<GENDER>(i);
|
||||||
if(!name_generator_[MALE]->is_valid()) {
|
name_generator_[i] = generator_factory.get_name_generator(gender_string(gender));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "utils/name_generator.hpp"
|
#include "utils/name_generator.hpp"
|
||||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
#include <memory>
|
||||||
|
|
||||||
class unit_race
|
class unit_race
|
||||||
{
|
{
|
||||||
|
@ -59,7 +59,7 @@ private:
|
||||||
t_string plural_name_;
|
t_string plural_name_;
|
||||||
t_string description_;
|
t_string description_;
|
||||||
unsigned int ntraits_;
|
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 traits_;
|
||||||
config::const_child_itors topics_;
|
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) :
|
context_free_grammar_generator::context_free_grammar_generator(const std::string& source)
|
||||||
initialized_(false)
|
|
||||||
{
|
{
|
||||||
const char* reading = source.c_str();
|
const char* reading = source.c_str();
|
||||||
nonterminal* current = nullptr;
|
nonterminal* current = nullptr;
|
||||||
|
@ -41,7 +40,11 @@ context_free_grammar_generator::context_free_grammar_generator(const std::string
|
||||||
while (*reading != 0) {
|
while (*reading != 0) {
|
||||||
if (*reading == '=') {
|
if (*reading == '=') {
|
||||||
// Leading and trailing whitespace is not significant, but internal whitespace is
|
// 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>());
|
current->possibilities_.push_back(std::vector<std::string>());
|
||||||
filled = ¤t->possibilities_.back();
|
filled = ¤t->possibilities_.back();
|
||||||
buf.clear();
|
buf.clear();
|
||||||
|
@ -53,8 +56,7 @@ context_free_grammar_generator::context_free_grammar_generator(const std::string
|
||||||
buf.clear();
|
buf.clear();
|
||||||
} else if (*reading == '|') {
|
} else if (*reading == '|') {
|
||||||
if (!filled || !current) {
|
if (!filled || !current) {
|
||||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced | symbol";
|
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced | symbol");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
filled->push_back(buf);
|
filled->push_back(buf);
|
||||||
current->possibilities_.push_back(std::vector<std::string>());
|
current->possibilities_.push_back(std::vector<std::string>());
|
||||||
|
@ -69,16 +71,14 @@ context_free_grammar_generator::context_free_grammar_generator(const std::string
|
||||||
} else {
|
} else {
|
||||||
if (*reading == '{') {
|
if (*reading == '{') {
|
||||||
if (!filled) {
|
if (!filled) {
|
||||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced { symbol";
|
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced { symbol");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
filled->push_back(buf);
|
filled->push_back(buf);
|
||||||
buf.clear();
|
buf.clear();
|
||||||
}
|
}
|
||||||
else if (*reading == '}') {
|
else if (*reading == '}') {
|
||||||
if (!filled) {
|
if (!filled) {
|
||||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced } symbol";
|
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced } symbol");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
filled->push_back('{' + utils::strip(buf));
|
filled->push_back('{' + utils::strip(buf));
|
||||||
buf.clear();
|
buf.clear();
|
||||||
|
@ -87,16 +87,16 @@ context_free_grammar_generator::context_free_grammar_generator(const std::string
|
||||||
reading++;
|
reading++;
|
||||||
}
|
}
|
||||||
if (filled) filled->push_back(buf);
|
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) :
|
context_free_grammar_generator::context_free_grammar_generator(const std::map<std::string, std::vector<std::string>>& source)
|
||||||
initialized_(false)
|
|
||||||
{
|
{
|
||||||
for(auto rule : source) {
|
for(auto rule : source) {
|
||||||
std::string key = rule.first; // Need to do this because utils::strip is mutating
|
std::string key = rule.first; // Need to do this because utils::strip is mutating
|
||||||
key = utils::strip(key);
|
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;
|
std::string buf;
|
||||||
for(std::string str : rule.second) {
|
for(std::string str : rule.second) {
|
||||||
nonterminals_[key].possibilities_.emplace_back();
|
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) {
|
for(char c : str) {
|
||||||
if (c == '{') {
|
if (c == '{') {
|
||||||
if (!filled) {
|
if (!filled) {
|
||||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced { symbol";
|
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced { symbol");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
filled->push_back(buf);
|
filled->push_back(buf);
|
||||||
buf.clear();
|
buf.clear();
|
||||||
}
|
}
|
||||||
else if (c == '}') {
|
else if (c == '}') {
|
||||||
if (!filled) {
|
if (!filled) {
|
||||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced } symbol";
|
throw name_generator_invalid_exception("[context_free_grammar_generator] Parsing error: misplaced } symbol");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filled->push_back('{' + utils::strip(buf));
|
filled->push_back('{' + utils::strip(buf));
|
||||||
buf.clear();
|
buf.clear();
|
||||||
} else buf.push_back(c);
|
} else buf.push_back(c);
|
||||||
|
@ -125,36 +124,51 @@ 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 context_free_grammar_generator::print_nonterminal(const std::string& name, uint32_t* seed, short seed_pos) const {
|
||||||
std::string result;
|
if (name == "!") {
|
||||||
std::map<std::string, nonterminal>::const_iterator found = nonterminals_.find(name);
|
return "|";
|
||||||
if (found == nonterminals_.end()) {
|
|
||||||
lg::wml_error() << "[context_free_grammar_generator] Warning: needed nonterminal " << name << " not defined";
|
|
||||||
return "!" + name;
|
|
||||||
}
|
}
|
||||||
const context_free_grammar_generator::nonterminal& got = found->second;
|
else if (name == "(" ) {
|
||||||
unsigned int picked = seed[seed_pos++] % got.possibilities_.size();
|
return "{";
|
||||||
if (seed_pos >= seed_size) seed_pos = 0;
|
}
|
||||||
if (picked == got.last_) {
|
else if (name == ")" ) {
|
||||||
picked = seed[seed_pos++] % got.possibilities_.size();
|
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";
|
||||||
|
return "!" + name;
|
||||||
|
}
|
||||||
|
const context_free_grammar_generator::nonterminal& got = found->second;
|
||||||
|
unsigned int picked = seed[seed_pos++] % got.possibilities_.size();
|
||||||
if (seed_pos >= seed_size) seed_pos = 0;
|
if (seed_pos >= seed_size) seed_pos = 0;
|
||||||
|
if (picked == got.last_) {
|
||||||
|
picked = seed[seed_pos++] % got.possibilities_.size();
|
||||||
|
if (seed_pos >= seed_size) seed_pos = 0;
|
||||||
|
}
|
||||||
|
got.last_ = picked;
|
||||||
|
const std::vector<std::string>& used = got.possibilities_[picked];
|
||||||
|
for (unsigned int i = 0; i < used.size(); i++) {
|
||||||
|
if (used[i][0] == '{') result += print_nonterminal(used[i].substr(1), seed, seed_pos);
|
||||||
|
else result += used[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
got.last_ = picked;
|
|
||||||
const std::vector<std::string>& used = got.possibilities_[picked];
|
|
||||||
for (unsigned int i = 0; i < used.size(); i++) {
|
|
||||||
if (used[i][0] == '{') result += print_nonterminal(used[i].substr(1), seed, seed_pos);
|
|
||||||
else result += used[i];
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string context_free_grammar_generator::generate() const {
|
std::string context_free_grammar_generator::generate() const {
|
||||||
uint32_t seed[seed_size];
|
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++) {
|
for (unsigned short int i = 0; i < seed_size; i++) {
|
||||||
seed[i] = random_new::generator->next_random();
|
seed[i] = random_new::generator->next_random();
|
||||||
}
|
}
|
||||||
return print_nonterminal("main", seed, 0);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@
|
||||||
|
|
||||||
#include "utils/name_generator.hpp"
|
#include "utils/name_generator.hpp"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -32,9 +30,9 @@ private:
|
||||||
mutable unsigned int last_;
|
mutable unsigned int last_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void init_seed(uint32_t seed[]) const;
|
||||||
std::map<std::string, nonterminal> nonterminals_;
|
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;
|
static const short unsigned int seed_size = 20;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -54,11 +52,6 @@ public:
|
||||||
std::string generate() const override;
|
std::string generate() const override;
|
||||||
|
|
||||||
~context_free_grammar_generator();
|
~context_free_grammar_generator();
|
||||||
|
|
||||||
/** Checks if the object is initialized
|
|
||||||
* @return if it is initialized
|
|
||||||
*/
|
|
||||||
bool is_valid() const override {return initialized_; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,21 +15,36 @@
|
||||||
#ifndef NAME_GENERATOR_HPP_INCLUDED
|
#ifndef NAME_GENERATOR_HPP_INCLUDED
|
||||||
#define NAME_GENERATOR_HPP_INCLUDED
|
#define NAME_GENERATOR_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include "global.hpp"
|
||||||
#include <string>
|
#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 {
|
class name_generator {
|
||||||
public:
|
public:
|
||||||
virtual std::string generate() const = 0;
|
std::string generate(const std::map<std::string,std::string>& variables) const { return utils::interpolate_variables_into_string(generate(), &variables); };
|
||||||
virtual bool is_valid() const {return true;}
|
virtual std::string generate() const { return ""; };
|
||||||
virtual ~name_generator() {}
|
name_generator() {};
|
||||||
|
virtual ~name_generator() {};
|
||||||
};
|
};
|
||||||
|
|
||||||
class proxy_name_generator : public name_generator {
|
class proxy_name_generator : public name_generator {
|
||||||
const name_generator& base;
|
const name_generator& base;
|
||||||
public:
|
public:
|
||||||
proxy_name_generator(const name_generator& b) : base(b) {}
|
proxy_name_generator(const name_generator& b) : base(b) {}
|
||||||
std::string generate() const override {return base.generate();}
|
std::string generate() const override { return base.generate(); };
|
||||||
bool is_valid() const override {return base.is_valid();}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#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