Merge pull request #661 from spixi/name_and_map_generator
Improvements in the name and map generators
This commit is contained in:
commit
7286ea8e0f
18 changed files with 469 additions and 319 deletions
|
@ -196,7 +196,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
|
||||
* Fix wesnoth.erase_unit failing if the unit was on a recall list.
|
||||
* WML tables defined in Lua now accept string keys with array values
|
||||
(where "array" is a table whose keys are all integers). This joins
|
||||
|
@ -331,6 +331,9 @@ Version 1.13.4+dev:
|
|||
passing to tomap() - this also means key-value pairs are now
|
||||
serializable (relevant in FormulaAI)
|
||||
* sgn(), trunc() and frac() functions for decimal numbers
|
||||
* 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_anon_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]
|
|
@ -109,6 +109,7 @@
|
|||
9164077D1D3C37D30057C4DE /* location_palette.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 914F2F841D35253900A42440 /* location_palette.cpp */; };
|
||||
9164077E1D3C37F60057C4DE /* chat_events.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 918C8A181D05F9AA009744A0 /* chat_events.cpp */; };
|
||||
9164077F1D3C381B0057C4DE /* chat_command_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 918C8A161D05F9AA009744A0 /* chat_command_handler.cpp */; };
|
||||
913D26771D3C9697002FF3AB /* name_generator_factory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 913D26751D3C9697002FF3AB /* name_generator_factory.cpp */; };
|
||||
916718E61CADA3BF00B055A9 /* connect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B5A9BCB00ECA805A002BE442 /* connect.cpp */; };
|
||||
916718E71CADA3BF00B055A9 /* description.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4944F4161354FBB20027E614 /* description.cpp */; };
|
||||
916718E81CADA3BF00B055A9 /* filter_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 620091C11575C784009AA2C9 /* filter_options.cpp */; };
|
||||
|
@ -1554,6 +1555,8 @@
|
|||
9130A45F1C73BB6100852782 /* select_orb_colors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = select_orb_colors.hpp; sourceTree = "<group>"; };
|
||||
914F2F841D35253900A42440 /* location_palette.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = location_palette.cpp; sourceTree = "<group>"; };
|
||||
914F2F851D35253900A42440 /* location_palette.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = location_palette.hpp; sourceTree = "<group>"; };
|
||||
913D26751D3C9697002FF3AB /* name_generator_factory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = name_generator_factory.cpp; sourceTree = "<group>"; };
|
||||
913D26761D3C9697002FF3AB /* name_generator_factory.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = name_generator_factory.hpp; sourceTree = "<group>"; };
|
||||
918056BE1CB1E4C0001A7F35 /* functional.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = functional.hpp; sourceTree = "<group>"; };
|
||||
918C8A161D05F9AA009744A0 /* chat_command_handler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = chat_command_handler.cpp; sourceTree = "<group>"; };
|
||||
918C8A171D05F9AA009744A0 /* chat_command_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = chat_command_handler.hpp; sourceTree = "<group>"; };
|
||||
|
@ -3580,6 +3583,8 @@
|
|||
91FBBAD91CB6D1B700470BFE /* markov_generator.cpp */,
|
||||
91FBBADA1CB6D1B700470BFE /* markov_generator.hpp */,
|
||||
91C55DA11CC078780040012E /* name_generator.hpp */,
|
||||
913D26751D3C9697002FF3AB /* name_generator_factory.cpp */,
|
||||
913D26761D3C9697002FF3AB /* name_generator_factory.hpp */,
|
||||
91EF6C001C9E22E400E2A733 /* reference_counter.hpp */,
|
||||
91EF6C011C9E22E400E2A733 /* sha1.cpp */,
|
||||
91EF6C021C9E22E400E2A733 /* sha1.hpp */,
|
||||
|
@ -5204,6 +5209,7 @@
|
|||
918C8A201D05F9AA009744A0 /* wesnothd_connection.cpp in Sources */,
|
||||
918C8A231D05FDAA009744A0 /* logging.cpp in Sources */,
|
||||
914F2F861D35253900A42440 /* location_palette.cpp in Sources */,
|
||||
913D26771D3C9697002FF3AB /* name_generator_factory.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -959,6 +959,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
|
||||
wesnothd_connection.cpp
|
||||
|
|
|
@ -562,6 +562,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
|
||||
wesnothd_connection.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");
|
||||
|
@ -41,14 +41,14 @@ static lg::log_domain log_mapgen("mapgen");
|
|||
|
||||
default_map_generator_job::default_map_generator_job()
|
||||
: 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)
|
||||
, game_config_(game_config_manager::get()->game_config())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -69,9 +69,7 @@ typedef map_location location;
|
|||
* the center of the map will be inverted (i.e. be valleys). 'island_size' as
|
||||
* 0 indicates no island.
|
||||
*/
|
||||
height_map default_map_generator_job::generate_height_map(size_t width, size_t height,
|
||||
size_t iterations, size_t hill_size,
|
||||
size_t island_size, size_t island_off_center)
|
||||
height_map default_map_generator_job::generate_height_map(size_t width, size_t height, size_t iterations, size_t hill_size, size_t island_size, size_t island_off_center)
|
||||
{
|
||||
height_map res(width, std::vector<int>(height,0));
|
||||
|
||||
|
@ -89,16 +87,18 @@ height_map default_map_generator_job::generate_height_map(size_t width, size_t h
|
|||
center_y += island_off_center;
|
||||
break;
|
||||
case 2:
|
||||
if(center_x < island_off_center)
|
||||
if(center_x < island_off_center) {
|
||||
center_x = 0;
|
||||
else
|
||||
} else {
|
||||
center_x -= island_off_center;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if(center_y < island_off_center)
|
||||
if(center_y < island_off_center) {
|
||||
center_y = 0;
|
||||
else
|
||||
} else {
|
||||
center_y -= island_off_center;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -118,10 +118,8 @@ height_map default_map_generator_job::generate_height_map(size_t width, size_t h
|
|||
// Is this a negative hill? (i.e. a valley)
|
||||
bool is_valley = false;
|
||||
|
||||
int x1 = island_size > 0 ? center_x - island_size + (rng_()%(island_size*2)) :
|
||||
int(rng_()%width);
|
||||
int y1 = island_size > 0 ? center_y - island_size + (rng_()%(island_size*2)) :
|
||||
int(rng_()%height);
|
||||
int x1 = island_size > 0 ? center_x - island_size + (rng_()%(island_size*2)) : int(rng_()%width);
|
||||
int y1 = island_size > 0 ? center_y - island_size + (rng_()%(island_size*2)) : int(rng_()%height);
|
||||
|
||||
// We have to check whether this is actually a valley
|
||||
if(island_size != 0) {
|
||||
|
@ -164,11 +162,13 @@ height_map default_map_generator_job::generate_height_map(size_t width, size_t h
|
|||
int heighest = 0, lowest = 100000, x;
|
||||
for(x = 0; size_t(x) != res.size(); ++x) {
|
||||
for(int y = 0; size_t(y) != res[x].size(); ++y) {
|
||||
if(res[x][y] > heighest)
|
||||
if(res[x][y] > heighest) {
|
||||
heighest = res[x][y];
|
||||
}
|
||||
|
||||
if(res[x][y] < lowest)
|
||||
if(res[x][y] < lowest) {
|
||||
lowest = res[x][y];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,8 +178,9 @@ height_map default_map_generator_job::generate_height_map(size_t width, size_t h
|
|||
for(int y = 0; size_t(y) != res[x].size(); ++y) {
|
||||
res[x][y] -= lowest;
|
||||
res[x][y] *= 1000;
|
||||
if(heighest != 0)
|
||||
if(heighest != 0) {
|
||||
res[x][y] /= heighest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,7 +274,7 @@ bool default_map_generator_job::generate_river_internal(const height_map& height
|
|||
|
||||
// Generate the river
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -379,7 +380,7 @@ namespace {
|
|||
struct road_path_calculator : pathfind::cost_calculator
|
||||
{
|
||||
road_path_calculator(const terrain_map& terrain, const config& cfg, int seed) :
|
||||
calls(0),
|
||||
calls(0),
|
||||
map_(terrain),
|
||||
cfg_(cfg),
|
||||
// Find out how windy roads should be.
|
||||
|
@ -404,7 +405,7 @@ double road_path_calculator::cost(const location& loc,
|
|||
const double /*so_far*/) const
|
||||
{
|
||||
++calls;
|
||||
if (loc.x < 0 || loc.y < 0 || loc.x >= static_cast<long>(map_.size()) ||
|
||||
if(loc.x < 0 || loc.y < 0 || loc.x >= static_cast<long>(map_.size()) ||
|
||||
loc.y >= static_cast<long>(map_.front().size())) {
|
||||
|
||||
return (pathfind::cost_calculator::getNoPathValue());
|
||||
|
@ -419,7 +420,7 @@ double road_path_calculator::cost(const location& loc,
|
|||
|
||||
double windiness = 1.0;
|
||||
|
||||
if (windiness_ > 1) {
|
||||
if(windiness_ > 1) {
|
||||
// modified pseudo_random taken from builder.cpp
|
||||
unsigned int a = (loc.x + 92872973) ^ 918273;
|
||||
unsigned int b = (loc.y + 1672517) ^ 128123;
|
||||
|
@ -441,7 +442,7 @@ double road_path_calculator::cost(const location& loc,
|
|||
static std::string terrain;
|
||||
terrain = t_translation::write_terrain_code(c);
|
||||
double res = getNoPathValue();
|
||||
if (const config &child = cfg_.find_child("road_cost", "terrain", terrain)) {
|
||||
if(const config &child = cfg_.find_child("road_cost", "terrain", terrain)) {
|
||||
res = child["cost"].to_double();
|
||||
}
|
||||
|
||||
|
@ -477,8 +478,7 @@ bool is_valid_terrain::operator()(int x, int y) const
|
|||
|
||||
}
|
||||
|
||||
static int rank_castle_location(int x, int y, const is_valid_terrain& valid_terrain, int min_x, int max_x, int min_y, int max_y,
|
||||
size_t min_distance, const std::vector<map_location>& other_castles, int highest_ranking)
|
||||
static int rank_castle_location(int x, int y, const is_valid_terrain& valid_terrain, int min_x, int max_x, int min_y, int max_y, size_t min_distance, const std::vector<map_location>& other_castles, int highest_ranking)
|
||||
{
|
||||
const map_location loc(x,y);
|
||||
|
||||
|
@ -517,8 +517,7 @@ static int rank_castle_location(int x, int y, const is_valid_terrain& valid_terr
|
|||
const int x_from_border = std::min<int>(x - min_x,max_x - x);
|
||||
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) +
|
||||
min_distance - 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;
|
||||
|
||||
int current_ranking = border_ranking*2 + avg_distance*10 + lowest_distance*10;
|
||||
static const int num_nearby_locations = 11*11;
|
||||
|
@ -564,10 +563,10 @@ static map_location place_village(const t_translation::t_map& map,
|
|||
|
||||
const t_translation::t_terrain t = map[i->x][i->y];
|
||||
const std::string str = t_translation::write_terrain_code(t);
|
||||
if (const config &child = cfg.find_child("village", "terrain", str)) {
|
||||
if(const config &child = cfg.find_child("village", "terrain", str)) {
|
||||
tcode_list_cache::iterator l = adj_liked_cache.find(t);
|
||||
t_translation::t_list *adjacent_liked;
|
||||
if (l != adj_liked_cache.end()) {
|
||||
if(l != adj_liked_cache.end()) {
|
||||
adjacent_liked = &(l->second);
|
||||
} else {
|
||||
adj_liked_cache[t] = t_translation::read_list(child["adjacent_liked"]);
|
||||
|
@ -599,35 +598,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() && name_generator != nullptr) {
|
||||
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,
|
||||
|
@ -637,10 +607,10 @@ static void flood_name(const map_location& start, const std::string& name, std::
|
|||
get_adjacent_tiles(start,adj);
|
||||
size_t n;
|
||||
//if adjacent tiles are tiles and unnamed, name them
|
||||
for (n = 0; n < 6; n++) {
|
||||
for(n = 0; n < 6; n++) {
|
||||
//we do not care for tiles outside the middle part
|
||||
//cast to unsigned to skip x < 0 || y < 0 as well.
|
||||
if (unsigned(adj[n].x) >= width / 3 || unsigned(adj[n].y) >= height / 3) {
|
||||
if(unsigned(adj[n].x) >= width / 3 || unsigned(adj[n].y) >= height / 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -649,7 +619,7 @@ static void flood_name(const map_location& start, const std::string& name, std::
|
|||
if((t_translation::terrain_matches(terr, tile_types)) && (tile_names.find(loc) == tile_names.end())) {
|
||||
tile_names.insert(std::pair<location, std::string>(loc, name));
|
||||
//labeling decision: this is result of trial and error on what looks best in game
|
||||
if (label_count % 6 == 0) { //ensure that labels do not occur more often than every 6 recursions
|
||||
if(label_count % 6 == 0) { //ensure that labels do not occur more often than every 6 recursions
|
||||
labels->insert(std::pair<map_location, std::string>(loc, full_name));
|
||||
label_count++; //ensure that no adjacent tiles get labeled
|
||||
}
|
||||
|
@ -732,8 +702,7 @@ terrain_converter::terrain_converter(const config& cfg)
|
|||
bool terrain_converter::convert_terrain(const t_translation::t_terrain & terrain,
|
||||
const int height, const int temperature) const
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
t_translation::t_terrain terrain_converter::convert_to() const
|
||||
|
@ -743,9 +712,7 @@ t_translation::t_terrain terrain_converter::convert_to() const
|
|||
|
||||
} // 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,
|
||||
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,
|
||||
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 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)
|
||||
{
|
||||
log_scope("map generation");
|
||||
|
@ -753,6 +720,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.
|
||||
|
@ -778,21 +752,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;
|
||||
|
@ -805,8 +803,7 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
size_t x, y;
|
||||
for(x = 0; x != heights.size(); ++x) {
|
||||
for(y = 0; y != heights[x].size(); ++y) {
|
||||
for(std::vector<terrain_height_mapper>::const_iterator i = height_conversion.begin();
|
||||
i != height_conversion.end(); ++i) {
|
||||
for(std::vector<terrain_height_mapper>::const_iterator i = height_conversion.begin(); i != height_conversion.end(); ++i) {
|
||||
if(i->convert_terrain(heights[x][y])) {
|
||||
terrain[x][y] = i->convert_to();
|
||||
break;
|
||||
|
@ -842,14 +839,14 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
for(int tries = 0; tries != 100; ++tries) {
|
||||
const int x = rng_()%width;
|
||||
const int y = rng_()%height;
|
||||
if (heights[x][y] > cfg["min_lake_height"].to_int()) {
|
||||
if(heights[x][y] > cfg["min_lake_height"].to_int()) {
|
||||
std::vector<location> river = generate_river(heights,
|
||||
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) {
|
||||
|
@ -872,8 +869,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;
|
||||
|
||||
|
@ -965,13 +962,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.
|
||||
|
@ -1047,7 +1037,7 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
std::set<location> bridges;
|
||||
|
||||
road_path_calculator calc(terrain, cfg, rng_());
|
||||
for (int road = 0; road != nroads; ++road) {
|
||||
for(int road = 0; road != nroads; ++road) {
|
||||
log_scope("creating road");
|
||||
|
||||
/*
|
||||
|
@ -1063,7 +1053,7 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
dst.x += width/3 - 1;
|
||||
dst.y += height/3 - 1;
|
||||
|
||||
if (roads_between_castles && road < int(castles.size() * castles.size())) {
|
||||
if(roads_between_castles && road < int(castles.size() * castles.size())) {
|
||||
const size_t src_castle = road/castles.size();
|
||||
const size_t dst_castle = road%castles.size();
|
||||
if(src_castle >= dst_castle) {
|
||||
|
@ -1079,15 +1069,15 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
continue;
|
||||
}
|
||||
|
||||
if (calc.cost(src, 0.0) >= 1000.0 || calc.cost(dst, 0.0) >= 1000.0) {
|
||||
if(calc.cost(src, 0.0) >= 1000.0 || calc.cost(dst, 0.0) >= 1000.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
|
@ -1109,8 +1099,7 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
|
||||
// Find the configuration which tells us
|
||||
// what to convert this tile to, to make it into a road.
|
||||
if (const config &child = cfg.find_child("road_cost", "terrain",
|
||||
t_translation::write_terrain_code(terrain[x][y])))
|
||||
if(const config &child = cfg.find_child("road_cost", "terrain", t_translation::write_terrain_code(terrain[x][y])))
|
||||
{
|
||||
// Convert to bridge means that we want to convert
|
||||
// depending upon the direction the road is going.
|
||||
|
@ -1151,8 +1140,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
|
||||
|
@ -1183,7 +1172,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1206,22 +1195,20 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
terrain[x][y] = t_translation::HUMAN_KEEP;
|
||||
|
||||
const int castles[13][2] = {
|
||||
{-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {0, 1}, {-1, 1},
|
||||
{-2, 1}, {-2, 0}, {-2, -1}, {-1, -2}, {0, -2}, {1, -2}
|
||||
{-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {0, 1}, {-1, 1},
|
||||
{-2, 1}, {-2, 0}, {-2, -1}, {-1, -2}, {0, -2}, {1, -2}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < castle_size - 1; i++) {
|
||||
terrain[x+castles[i][0]][y+castles[i][1]] = t_translation::HUMAN_CASTLE;
|
||||
for(size_t i = 0; i < castle_size - 1; i++) {
|
||||
terrain[x+castles[i][0]][y+castles[i][1]] = t_translation::HUMAN_CASTLE;
|
||||
}
|
||||
|
||||
// Remove all labels under the castle tiles
|
||||
if(labels != nullptr) {
|
||||
labels->erase(location(x-width/3,y-height/3));
|
||||
for (size_t i = 0; i < castle_size - 1; i++) {
|
||||
labels->erase(location(x+castles[i][0]-width/3,
|
||||
y+castles[i][1]-height/3));
|
||||
}
|
||||
|
||||
labels->erase(location(x-width/3,y-height/3));
|
||||
for(size_t i = 0; i < castle_size - 1; i++) {
|
||||
labels->erase(location(x+castles[i][0]-width/3, y+castles[i][1]-height/3));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1233,72 +1220,57 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
*we name these now that everything else is placed (as e.g., placing
|
||||
* roads could split a forest)
|
||||
*/
|
||||
if ( misc_labels != nullptr ) {
|
||||
for (x = width / 3; x < (width / 3)*2; x++) {
|
||||
for (y = height / 3; y < (height / 3) * 2;y++) {
|
||||
if(misc_labels != nullptr) {
|
||||
for(x = width / 3; x < (width / 3)*2; x++) {
|
||||
for(y = height / 3; y < (height / 3) * 2;y++) {
|
||||
//check the terrain of the tile
|
||||
const location loc(x - width / 3, y - height / 3);
|
||||
const t_translation::t_terrain terr = terrain[x][y];
|
||||
std::string name, base_name;
|
||||
std::set<std::string> used_names;
|
||||
if (t_translation::terrain_matches(terr, t_translation::ALL_MOUNTAINS)) {
|
||||
if(t_translation::terrain_matches(terr, t_translation::ALL_MOUNTAINS)) {
|
||||
//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) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
else if (t_translation::terrain_matches(terr, t_translation::ALL_FORESTS)) {
|
||||
else if(t_translation::terrain_matches(terr, t_translation::ALL_FORESTS)) {
|
||||
//if the forest tile is not named yet, name it
|
||||
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
|
||||
flood_name(loc, base_name, forest_names, t_translation::ALL_FORESTS, terrain, width, height, 0, misc_labels, name);
|
||||
}
|
||||
}
|
||||
else if (t_translation::terrain_matches(terr, t_translation::ALL_SWAMPS)) {
|
||||
else if(t_translation::terrain_matches(terr, t_translation::ALL_SWAMPS)) {
|
||||
//if the swamp tile is not named yet, name it
|
||||
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
|
||||
flood_name(loc, base_name, swamp_names, t_translation::ALL_SWAMPS, terrain, width, height, 0, misc_labels, name);
|
||||
}
|
||||
}
|
||||
}//for (y)
|
||||
}//for (x)
|
||||
}//if (misc_labels)
|
||||
}//for(y)
|
||||
}//for(x)
|
||||
}//if(misc_labels)
|
||||
|
||||
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
|
||||
const size_t tiles_per_village = ((width*height)/9)/nvillages;
|
||||
size_t village_x = 1, village_y = 1;
|
||||
|
@ -1317,6 +1289,17 @@ 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) {
|
||||
|
@ -1335,7 +1318,7 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
|
||||
const std::string str =
|
||||
t_translation::write_terrain_code(terrain[res.x][res.y]);
|
||||
if (const config &child = cfg.find_child("village", "terrain", str))
|
||||
if(const config &child = cfg.find_child("village", "terrain", str))
|
||||
{
|
||||
const std::string &convert_to = child["convert_to"];
|
||||
if(convert_to != "") {
|
||||
|
@ -1344,42 +1327,50 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
|
||||
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_anon", "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),
|
||||
field = t_translation::t_list(1, t_translation::GRASS_LAND),
|
||||
forest = t_translation::t_list(1, t_translation::FOREST),
|
||||
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;
|
||||
|
||||
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";
|
||||
//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 = "river_bridge";
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -1388,28 +1379,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;
|
||||
}
|
||||
|
||||
|
@ -1429,19 +1420,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 = "mountain_anon";
|
||||
} 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
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "utils/functional.hpp"
|
||||
#include "utils/name_generator.hpp"
|
||||
#include "utils/markov_generator.hpp"
|
||||
#include "utils/context_free_grammar_generator.hpp"
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
@ -186,61 +187,60 @@ static int intf_name_generator(lua_State *L)
|
|||
{
|
||||
std::string type = luaL_checkstring(L, 1);
|
||||
name_generator* gen = nullptr;
|
||||
if(type == "markov" || type == "markov_chain") {
|
||||
std::vector<std::string> input;
|
||||
if(lua_istable(L, 2)) {
|
||||
input = lua_check<std::vector<std::string>>(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);
|
||||
}
|
||||
try {
|
||||
if(type == "markov" || type == "markov_chain") {
|
||||
std::vector<std::string> input;
|
||||
if(lua_istable(L, 2)) {
|
||||
input = lua_check<std::vector<std::string>>(L, 2);
|
||||
} else {
|
||||
input = utils::parenthetical_split(luaL_checkstring(L, 2), ',');
|
||||
}
|
||||
if(!data.empty()) {
|
||||
gen = new(buf) context_free_grammar_generator(data);
|
||||
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()) {
|
||||
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 {
|
||||
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";
|
||||
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, Gen);
|
||||
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,17 @@ 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();
|
||||
std::vector<std::string>* filled = &nonterminals_[key].possibilities_.back();
|
||||
|
@ -105,17 +106,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,36 +125,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 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;
|
||||
if (name == "!") {
|
||||
return "|";
|
||||
}
|
||||
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 (picked == got.last_) {
|
||||
picked = seed[seed_pos++] % got.possibilities_.size();
|
||||
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";
|
||||
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 (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 {
|
||||
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>
|
||||
#include <cstdint>
|
||||
|
@ -33,9 +31,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:
|
||||
|
@ -55,11 +53,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,12 +15,27 @@
|
|||
#ifndef NAME_GENERATOR_HPP_INCLUDED
|
||||
#define NAME_GENERATOR_HPP_INCLUDED
|
||||
|
||||
#include "global.hpp"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <exception>
|
||||
|
||||
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;}
|
||||
// Defined in name_generator_factory.cpp
|
||||
std::string generate(const std::map<std::string,std::string>& variables) const;
|
||||
virtual std::string generate() const { return ""; }
|
||||
name_generator() {}
|
||||
virtual ~name_generator() {}
|
||||
};
|
||||
|
||||
|
@ -28,8 +43,7 @@ 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
|
||||
|
|
75
src/utils/name_generator_factory.cpp
Normal file
75
src/utils/name_generator_factory.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
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"
|
||||
#include "formula/string_utils.hpp"
|
||||
|
||||
std::string name_generator::generate(const std::map<std::string,std::string>& variables) const {
|
||||
return utils::interpolate_variables_into_string(generate(), &variables);
|
||||
}
|
||||
|
||||
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