Lua API for the name generators
This commit is contained in:
parent
a9dbbe9c05
commit
1649930113
19 changed files with 474 additions and 188 deletions
|
@ -139,6 +139,9 @@ Version 1.13.4+dev:
|
|||
sources. The [sound_source] and [remove_sound_source] now use these.
|
||||
* New wesnoth.log function for printing log messages. The [wml_message]
|
||||
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
|
||||
* WML tables defined in Lua now accept string keys with array values
|
||||
(where "array" is a table whose keys are all integers). This joins
|
||||
the elements of the array with commas and produces a single string
|
||||
|
|
|
@ -135,6 +135,7 @@
|
|||
916719061CADABEA00B055A9 /* game_data.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC387E68195AFB1F00FC0342 /* game_data.cpp */; };
|
||||
916719071CADAC0D00B055A9 /* libboost_randomw.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EC64D75C1A085C990092EF75 /* libboost_randomw.dylib */; };
|
||||
916719081CADAC2800B055A9 /* apple_notification.mm in Sources */ = {isa = PBXBuildFile; fileRef = F40A13BB1A3A88BA00C4D071 /* apple_notification.mm */; };
|
||||
916B7E941CC151FA00811097 /* race.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999C00EC62181008DD061 /* race.cpp */; };
|
||||
919B37F81BAF789E00E0094C /* synced_user_choice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919B37F71BAF789D00E0094C /* synced_user_choice.cpp */; };
|
||||
919B37FC1BAF7A9D00E0094C /* synced_choice_wait.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 919B37FA1BAF7A9D00E0094C /* synced_choice_wait.cpp */; };
|
||||
91A214E51CAD666B00927AEA /* arrow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B52EE8A1121359A600CFBDAB /* arrow.cpp */; };
|
||||
|
@ -448,6 +449,7 @@
|
|||
91B622221B76C0F400B00E0F /* libboost_regexw.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F4EF0D5313AD4E35003C701D /* libboost_regexw.dylib */; };
|
||||
91B622231B76C0F400B00E0F /* libboost_systemw.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F4EF0D5413AD4E35003C701D /* libboost_systemw.dylib */; };
|
||||
91B622241B76C0F400B00E0F /* libboost_threadw.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F4EF0D5B13AD4E6D003C701D /* libboost_threadw.dylib */; };
|
||||
91C55DA41CC078820040012E /* context_free_grammar_generator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C55DA21CC078820040012E /* context_free_grammar_generator.cpp */; };
|
||||
91DCA6891C9066CC0030F8D0 /* unit_preview_pane.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91DCA6871C9066CC0030F8D0 /* unit_preview_pane.cpp */; };
|
||||
91DCA68D1C9066EC0030F8D0 /* unit_recruit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91DCA68B1C9066EC0030F8D0 /* unit_recruit.cpp */; };
|
||||
91E355631CACA1CE00774252 /* libboost_unit_test_frameworkw.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 91E355621CACA1CE00774252 /* libboost_unit_test_frameworkw.dylib */; };
|
||||
|
@ -718,6 +720,7 @@
|
|||
91F462881C7115C50050A9C9 /* combobox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91F462861C7115C50050A9C9 /* combobox.cpp */; };
|
||||
91F462941C7117400050A9C9 /* drop_down_list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91F462921C7117400050A9C9 /* drop_down_list.cpp */; };
|
||||
91FAC70A1C7FBC3400DAB2C3 /* lua_formula_bridge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91FAC7091C7FBC2C00DAB2C3 /* lua_formula_bridge.cpp */; };
|
||||
91FBBADB1CB6D1B700470BFE /* markov_generator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91FBBAD91CB6D1B700470BFE /* markov_generator.cpp */; };
|
||||
B504B94C1284C06B00261FE9 /* tips.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B504B94A1284C06B00261FE9 /* tips.cpp */; };
|
||||
B508D13F10013BF900B12852 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B508D13E10013BF900B12852 /* Growl.framework */; };
|
||||
B508D14B10013E4700B12852 /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = B508D14A10013E4700B12852 /* Growl Registration Ticket.growlRegDict */; };
|
||||
|
@ -841,7 +844,6 @@
|
|||
B5599B0B0EC62181008DD061 /* reports.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999B70EC62181008DD061 /* reports.cpp */; };
|
||||
B5599B0C0EC62181008DD061 /* replay_controller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999B90EC62181008DD061 /* replay_controller.cpp */; };
|
||||
B5599B0D0EC62181008DD061 /* replay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999BB0EC62181008DD061 /* replay.cpp */; };
|
||||
B5599B0F0EC62181008DD061 /* race.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999C00EC62181008DD061 /* race.cpp */; };
|
||||
B5599B100EC62181008DD061 /* preferences_display.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999C20EC62181008DD061 /* preferences_display.cpp */; };
|
||||
B5599B110EC62181008DD061 /* preferences.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999C40EC62181008DD061 /* preferences.cpp */; };
|
||||
B5599B130EC62181008DD061 /* playturn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999C80EC62181008DD061 /* playturn.cpp */; };
|
||||
|
@ -1671,6 +1673,9 @@
|
|||
91B621F51B76BCB000B00E0F /* unicode_cast.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unicode_cast.hpp; sourceTree = "<group>"; };
|
||||
91B621F61B76BCB000B00E0F /* unicode_types.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unicode_types.hpp; sourceTree = "<group>"; };
|
||||
91B621F71B76BD4600B00E0F /* multimenu.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = multimenu.hpp; sourceTree = "<group>"; };
|
||||
91C55DA11CC078780040012E /* name_generator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = name_generator.hpp; sourceTree = "<group>"; };
|
||||
91C55DA21CC078820040012E /* context_free_grammar_generator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = context_free_grammar_generator.cpp; sourceTree = "<group>"; };
|
||||
91C55DA31CC078820040012E /* context_free_grammar_generator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = context_free_grammar_generator.hpp; sourceTree = "<group>"; };
|
||||
91DCA6871C9066CC0030F8D0 /* unit_preview_pane.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unit_preview_pane.cpp; sourceTree = "<group>"; };
|
||||
91DCA6881C9066CC0030F8D0 /* unit_preview_pane.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = unit_preview_pane.hpp; sourceTree = "<group>"; };
|
||||
91DCA68B1C9066EC0030F8D0 /* unit_recruit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = unit_recruit.cpp; sourceTree = "<group>"; };
|
||||
|
@ -1716,6 +1721,8 @@
|
|||
91FAC7081C7F931900DAB2C3 /* lua_formula_bridge.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = lua_formula_bridge.hpp; sourceTree = "<group>"; };
|
||||
91FAC7091C7FBC2C00DAB2C3 /* lua_formula_bridge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lua_formula_bridge.cpp; sourceTree = "<group>"; };
|
||||
91FAC70B1C80168600DAB2C3 /* group.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = group.hpp; sourceTree = "<group>"; };
|
||||
91FBBAD91CB6D1B700470BFE /* markov_generator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = markov_generator.cpp; sourceTree = "<group>"; };
|
||||
91FBBADA1CB6D1B700470BFE /* markov_generator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = markov_generator.hpp; sourceTree = "<group>"; };
|
||||
B504B94A1284C06B00261FE9 /* tips.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tips.cpp; sourceTree = "<group>"; };
|
||||
B504B94B1284C06B00261FE9 /* tips.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = tips.hpp; sourceTree = "<group>"; };
|
||||
B508D13E10013BF900B12852 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = lib/Growl.framework; sourceTree = "<group>"; };
|
||||
|
@ -3001,8 +3008,6 @@
|
|||
B55999C10EC62181008DD061 /* preferences_display.hpp */,
|
||||
ECC84C1B1B973C5900A5F451 /* quit_confirmation.cpp */,
|
||||
ECC84C1C1B973C5900A5F451 /* quit_confirmation.hpp */,
|
||||
B55999C00EC62181008DD061 /* race.cpp */,
|
||||
B55999BF0EC62181008DD061 /* race.hpp */,
|
||||
EC84245B18F30D9100FC1EEF /* random_new.cpp */,
|
||||
EC84245C18F30D9100FC1EEF /* random_new.hpp */,
|
||||
EC84245718F30D9000FC1EEF /* random_new_deterministic.cpp */,
|
||||
|
@ -3565,11 +3570,16 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
91EF6BFC1C9E22E400E2A733 /* const_clone.hpp */,
|
||||
91C55DA21CC078820040012E /* context_free_grammar_generator.cpp */,
|
||||
91C55DA31CC078820040012E /* context_free_grammar_generator.hpp */,
|
||||
918056BE1CB1E4C0001A7F35 /* functional.hpp */,
|
||||
911F471B1CAE5A7E00F47035 /* iterable_pair.hpp */,
|
||||
91EF6BFF1C9E22E400E2A733 /* iterator.hpp */,
|
||||
EC53B04D1B23BB0E002F758F /* make_enum.cpp */,
|
||||
91B621931B76720B00B00E0F /* make_enum.hpp */,
|
||||
91FBBAD91CB6D1B700470BFE /* markov_generator.cpp */,
|
||||
91FBBADA1CB6D1B700470BFE /* markov_generator.hpp */,
|
||||
91C55DA11CC078780040012E /* name_generator.hpp */,
|
||||
91EF6C001C9E22E400E2A733 /* reference_counter.hpp */,
|
||||
91EF6C011C9E22E400E2A733 /* sha1.cpp */,
|
||||
91EF6C021C9E22E400E2A733 /* sha1.hpp */,
|
||||
|
@ -3648,6 +3658,8 @@
|
|||
B55999730EC62181008DD061 /* map.cpp */,
|
||||
B55999720EC62181008DD061 /* map.hpp */,
|
||||
91B6219C1B76735200B00E0F /* ptr.hpp */,
|
||||
B55999C00EC62181008DD061 /* race.cpp */,
|
||||
B55999BF0EC62181008DD061 /* race.hpp */,
|
||||
B55999710EC62181008DD061 /* types.cpp */,
|
||||
B55999700EC62181008DD061 /* types.hpp */,
|
||||
B55999790EC62181008DD061 /* udisplay.cpp */,
|
||||
|
@ -5016,7 +5028,6 @@
|
|||
B52EE89E1213590500CFBDAB /* progress_bar.cpp in Sources */,
|
||||
B5599ADC0EC62181008DD061 /* progressbar.cpp in Sources */,
|
||||
62CC8E7817B9063E00C16B75 /* pump.cpp in Sources */,
|
||||
B5599B0F0EC62181008DD061 /* race.cpp in Sources */,
|
||||
EC84246718F30D9100FC1EEF /* random_new_deterministic.cpp in Sources */,
|
||||
EC84246818F30D9100FC1EEF /* random_new_synced.cpp in Sources */,
|
||||
EC84246918F30D9100FC1EEF /* random_new.cpp in Sources */,
|
||||
|
@ -5186,6 +5197,9 @@
|
|||
91DCA68D1C9066EC0030F8D0 /* unit_recruit.cpp in Sources */,
|
||||
9122417C1CAAB7B7008B347F /* loadscreen.cpp in Sources */,
|
||||
91FAC70A1C7FBC3400DAB2C3 /* lua_formula_bridge.cpp in Sources */,
|
||||
91FBBADB1CB6D1B700470BFE /* markov_generator.cpp in Sources */,
|
||||
91C55DA41CC078820040012E /* context_free_grammar_generator.cpp in Sources */,
|
||||
916B7E941CC151FA00811097 /* race.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -980,9 +980,11 @@ set(wesnoth-main_SRC
|
|||
units/helper.cpp
|
||||
units/id.cpp
|
||||
units/map.cpp
|
||||
units/race.cpp
|
||||
units/types.cpp
|
||||
utils/sha1.cpp
|
||||
utils/context_free_grammar_generator.cpp
|
||||
utils/markov_generator.cpp
|
||||
variable.cpp
|
||||
variable_info.cpp
|
||||
whiteboard/action.cpp
|
||||
|
@ -1039,7 +1041,6 @@ set(libwesnoth-game_STAT_SRC
|
|||
pathutils.cpp
|
||||
preferences.cpp
|
||||
preferences_display.cpp
|
||||
race.cpp
|
||||
quit_confirmation.cpp
|
||||
reports.cpp
|
||||
show_dialog.cpp
|
||||
|
|
|
@ -120,7 +120,6 @@ libwesnoth_sources = Split("""
|
|||
pathutils.cpp
|
||||
preferences.cpp
|
||||
quit_confirmation.cpp
|
||||
race.cpp
|
||||
reports.cpp
|
||||
show_dialog.cpp
|
||||
sound_music_track.cpp
|
||||
|
@ -552,11 +551,13 @@ wesnoth_sources = Split("""
|
|||
units/helper.cpp
|
||||
units/id.cpp
|
||||
units/map.cpp
|
||||
units/race.cpp
|
||||
units/types.cpp
|
||||
units/udisplay.cpp
|
||||
units/unit.cpp
|
||||
utils/sha1.cpp
|
||||
utils/context_free_grammar_generator.cpp
|
||||
utils/markov_generator.cpp
|
||||
variable_info.cpp
|
||||
variable.cpp
|
||||
whiteboard/action.cpp
|
||||
|
|
|
@ -27,10 +27,11 @@
|
|||
#include "default_map_generator_job.hpp"
|
||||
#include "pathfind/pathfind.hpp"
|
||||
#include "pathutils.hpp"
|
||||
#include "race.hpp"
|
||||
#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 <SDL.h>
|
||||
|
||||
#include "seed_rng.hpp"
|
||||
|
@ -601,14 +602,14 @@ static map_location place_village(const t_translation::t_map& map,
|
|||
return best_loc;
|
||||
}
|
||||
|
||||
std::string default_map_generator_job::generate_name(const unit_race& name_generator, const std::string& id,
|
||||
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_name(unit_race::MALE);
|
||||
const std::string& name = name_generator->generate();
|
||||
LOG_NG << "name generator returned '" << name << "'\n";
|
||||
if(base_name != nullptr) {
|
||||
*base_name = name;
|
||||
|
@ -783,12 +784,19 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
config naming = cfg.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;
|
||||
// HACK: dummy names to satisfy unit_race requirements
|
||||
naming["id"] = "village_naming";
|
||||
naming["plural_name"] = "villages";
|
||||
|
||||
// Make a dummy race for generating names
|
||||
const unit_race name_generator(naming);
|
||||
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();
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
std::vector<terrain_height_mapper> height_conversion;
|
||||
|
||||
|
@ -1279,11 +1287,20 @@ std::string default_map_generator_job::default_generate_map(size_t width, size_t
|
|||
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;
|
||||
// HACK: dummy names to satisfy unit_race requirements
|
||||
naming_cfg["id"] = "village_naming";
|
||||
naming_cfg["plural_name"] = "villages";
|
||||
|
||||
const unit_race village_names_generator(naming_cfg);
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -24,12 +24,13 @@ class unit_race;
|
|||
#include "map/location.hpp"
|
||||
#include "terrain/translation.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "utils/name_generator.hpp"
|
||||
|
||||
#include <boost/random.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <map>
|
||||
|
||||
|
||||
class default_map_generator_job
|
||||
{
|
||||
public:
|
||||
|
@ -59,7 +60,7 @@ 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(const unit_race& name_generator, const std::string& id,
|
||||
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);
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
#include "gui/dialogs/dialog.hpp"
|
||||
#include "gui/widgets/group.hpp"
|
||||
#include "race.hpp"
|
||||
#include "units/race.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include "utils/make_enum.hpp" // for operator<<
|
||||
#include "map/map.hpp" // for gamemap
|
||||
#include "marked-up_text.hpp" // for is_cjk_char, word_wrap_text
|
||||
#include "race.hpp" // for unit_race, etc
|
||||
#include "units/race.hpp" // for unit_race, etc
|
||||
#include "resources.hpp" // for tod_manager, config_manager
|
||||
#include "sdl/utils.hpp" // for surface
|
||||
#include "serialization/string_utils.hpp" // for split, quoted_split, etc
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "language.hpp" // for string_table, symbol_table
|
||||
#include "log.hpp" // for LOG_STREAM, logger, etc
|
||||
#include "movetype.hpp" // for movetype, movetype::effects, etc
|
||||
#include "race.hpp" // for unit_race, etc
|
||||
#include "units/race.hpp" // for unit_race, etc
|
||||
#include "terrain/terrain.hpp" // for terrain_type
|
||||
#include "terrain/translation.hpp" // for operator==, t_list, etc
|
||||
#include "terrain/type_data.hpp" // for terrain_type_data, etc
|
||||
|
|
|
@ -104,6 +104,8 @@
|
|||
#include "units/ptr.hpp" // for unit_const_ptr, unit_ptr
|
||||
#include "units/types.hpp" // for unit_type_data, unit_types, etc
|
||||
#include "util.hpp" // for lexical_cast
|
||||
#include "utils/markov_generator.hpp"
|
||||
#include "utils/context_free_grammar_generator.hpp"
|
||||
#include "variable.hpp" // for vconfig, etc
|
||||
#include "variable_info.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
|
@ -4368,6 +4370,69 @@ int game_lua_kernel::intf_toggle_fog(lua_State *L, const bool clear)
|
|||
return 0;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
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);
|
||||
return lua_error(L);
|
||||
}
|
||||
// We set the metatable now, even if the generator is invalid, so that it
|
||||
// will be properly collected if it was invalid.
|
||||
luaL_getmetatable(L, "name generator");
|
||||
lua_setmetatable(L, -2);
|
||||
if(!gen->is_valid()) {
|
||||
lua_pushstring(L, generic_err);
|
||||
return lua_error(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// END CALLBACK IMPLEMENTATION
|
||||
|
||||
game_board & game_lua_kernel::board() {
|
||||
|
@ -4450,6 +4515,7 @@ game_lua_kernel::game_lua_kernel(CVideo * video, game_state & gs, play_controlle
|
|||
{ "get_traits", &intf_get_traits },
|
||||
{ "get_viewing_side", &intf_get_viewing_side },
|
||||
{ "modify_ai", &intf_modify_ai },
|
||||
{ "name_generator", &intf_name_generator },
|
||||
{ "set_music", &intf_set_music },
|
||||
{ "transform_unit", &intf_transform_unit },
|
||||
{ "unit_ability", &intf_unit_ability },
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
|
||||
#include "scripting/lua_race.hpp"
|
||||
|
||||
#include "race.hpp"
|
||||
#include "units/race.hpp"
|
||||
#include "scripting/lua_common.hpp"
|
||||
#include "units/types.hpp"
|
||||
#include "utils/name_generator.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
@ -30,6 +31,7 @@
|
|||
|
||||
// Registry key
|
||||
static const char * Race = "race";
|
||||
static const char * Gen = "name generator";
|
||||
|
||||
/**
|
||||
* Gets some data on a race (__index metamethod).
|
||||
|
@ -71,10 +73,38 @@ static int impl_race_get(lua_State* L)
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(m, "male_name_gen") == 0) {
|
||||
new(lua_newuserdata(L, sizeof(proxy_name_generator)))
|
||||
proxy_name_generator(race.generator(unit_race::MALE));
|
||||
luaL_getmetatable(L, Gen);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(m, "female_name_gen") == 0) {
|
||||
new(lua_newuserdata(L, sizeof(proxy_name_generator)))
|
||||
proxy_name_generator(race.generator(unit_race::FEMALE));
|
||||
luaL_getmetatable(L, Gen);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int impl_name_generator_call(lua_State *L)
|
||||
{
|
||||
name_generator* gen = static_cast<name_generator*>(lua_touserdata(L, 1));
|
||||
lua_pushstring(L, gen->generate().c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int impl_name_generator_collect(lua_State *L)
|
||||
{
|
||||
name_generator* gen = static_cast<name_generator*>(lua_touserdata(L, 1));
|
||||
gen->~name_generator();
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace lua_race {
|
||||
|
||||
std::string register_metatable(lua_State * L)
|
||||
|
@ -89,6 +119,14 @@ namespace lua_race {
|
|||
|
||||
lua_pushstring(L, "race");
|
||||
lua_setfield(L, -2, "__metatable");
|
||||
|
||||
luaL_newmetatable(L, Gen);
|
||||
static luaL_Reg const generator[] = {
|
||||
{ "__call", &impl_name_generator_call},
|
||||
{ "__gc", &impl_name_generator_collect},
|
||||
{ nullptr, nullptr}
|
||||
};
|
||||
luaL_setfuncs(L, generator, 0);
|
||||
|
||||
return "Adding getrace metatable...\n";
|
||||
}
|
||||
|
|
168
src/units/race.cpp
Normal file
168
src/units/race.cpp
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
Copyright (C) 2003 - 2016 by David White <dave@whitevine.net>
|
||||
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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Generate race-specific unit-names.
|
||||
*/
|
||||
|
||||
#include "global.hpp"
|
||||
|
||||
#include "units/race.hpp"
|
||||
|
||||
#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"
|
||||
|
||||
/// Dummy race used when a race is not yet known.
|
||||
const unit_race unit_race::null_race;
|
||||
/// Standard string id (not translatable) for FEMALE
|
||||
const std::string unit_race::s_female("female");
|
||||
/// Standard string id (not translatable) for MALE
|
||||
const std::string unit_race::s_male("male");
|
||||
|
||||
|
||||
static const config &empty_traits() {
|
||||
static config cfg;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static const config &empty_topics() {
|
||||
static config cfg;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
unit_race::unit_race() :
|
||||
cfg_(),
|
||||
id_(),
|
||||
plural_name_(),
|
||||
description_(),
|
||||
ntraits_(0),
|
||||
traits_(empty_traits().child_range("trait")),
|
||||
topics_(empty_topics().child_range("topic")),
|
||||
global_traits_(true),
|
||||
undead_variation_()
|
||||
{
|
||||
name_[MALE] = "";
|
||||
name_[FEMALE] = "";
|
||||
}
|
||||
|
||||
unit_race::unit_race(const config& cfg) :
|
||||
cfg_(cfg),
|
||||
id_(cfg["id"]),
|
||||
plural_name_(cfg["plural_name"].t_str()),
|
||||
description_(cfg["description"].t_str()),
|
||||
ntraits_(cfg["num_traits"]),
|
||||
traits_(cfg.child_range("trait")),
|
||||
topics_(cfg.child_range("topic")),
|
||||
global_traits_(!cfg["ignore_global_traits"].to_bool()),
|
||||
undead_variation_(cfg["undead_variation"])
|
||||
|
||||
{
|
||||
if (id_.empty()) {
|
||||
lg::wml_error() << "[race] '" << cfg["name"] << "' is missing an id field.";
|
||||
}
|
||||
if (plural_name_.empty()) {
|
||||
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()) {
|
||||
name_[MALE] = (cfg["name"]);
|
||||
}
|
||||
name_[FEMALE] = cfg["female_name"];
|
||||
if(name_[FEMALE].empty()) {
|
||||
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"];
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
std::string unit_race::generate_name(unit_race::GENDER gender) const
|
||||
{
|
||||
return name_generator_[gender]->generate();
|
||||
}
|
||||
|
||||
const name_generator& unit_race::generator(unit_race::GENDER gender) const
|
||||
{
|
||||
return *name_generator_[gender];
|
||||
}
|
||||
|
||||
bool unit_race::uses_global_traits() const
|
||||
{
|
||||
return global_traits_;
|
||||
}
|
||||
|
||||
const config::const_child_itors &unit_race::additional_traits() const
|
||||
{
|
||||
return traits_;
|
||||
}
|
||||
|
||||
const config::const_child_itors &unit_race::additional_topics() const
|
||||
{
|
||||
return topics_;
|
||||
}
|
||||
|
||||
unsigned int unit_race::num_traits() const { return ntraits_; }
|
||||
|
||||
|
||||
std::string const& gender_string(unit_race::GENDER gender) {
|
||||
switch(gender) {
|
||||
case unit_race::FEMALE:
|
||||
return unit_race::s_female;
|
||||
default:
|
||||
case unit_race::MALE:
|
||||
return unit_race::s_male;
|
||||
}
|
||||
}
|
||||
|
||||
unit_race::GENDER string_gender(const std::string& str, unit_race::GENDER def) {
|
||||
if ( str == unit_race::s_male ) {
|
||||
return unit_race::MALE;
|
||||
} else if ( str == unit_race::s_female ) {
|
||||
return unit_race::FEMALE;
|
||||
}
|
||||
return def;
|
||||
}
|
|
@ -16,10 +16,8 @@
|
|||
#define RACE_HPP_INCLUDED
|
||||
|
||||
#include "config.hpp"
|
||||
#include "serialization/unicode_types.hpp"
|
||||
#include "utils/context_free_grammar_generator.hpp"
|
||||
|
||||
typedef std::map<ucs4::string, ucs4::string > markov_prefix_map;
|
||||
#include "utils/name_generator.hpp"
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
|
||||
class unit_race
|
||||
{
|
||||
|
@ -38,6 +36,7 @@ public:
|
|||
const t_string& description() const { return description_; }
|
||||
|
||||
std::string generate_name(GENDER gender) const;
|
||||
const name_generator& generator(GENDER gender) const;
|
||||
|
||||
bool uses_global_traits() const;
|
||||
|
||||
|
@ -60,9 +59,7 @@ private:
|
|||
t_string plural_name_;
|
||||
t_string description_;
|
||||
unsigned int ntraits_;
|
||||
markov_prefix_map next_[NUM_GENDERS];
|
||||
int chain_size_;
|
||||
context_free_grammar_generator name_generator_[NUM_GENDERS];
|
||||
boost::shared_ptr<name_generator> name_generator_[NUM_GENDERS];
|
||||
|
||||
config::const_child_itors traits_;
|
||||
config::const_child_itors topics_;
|
|
@ -18,7 +18,7 @@
|
|||
#include "utils/make_enum.hpp"
|
||||
#include "map/location.hpp"
|
||||
#include "movetype.hpp"
|
||||
#include "race.hpp"
|
||||
#include "units/race.hpp"
|
||||
#include "units/attack_type.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
|
|
|
@ -19,21 +19,20 @@
|
|||
*/
|
||||
|
||||
#include "context_free_grammar_generator.hpp"
|
||||
#include "../log.hpp"
|
||||
#include "../random_new.hpp"
|
||||
|
||||
context_free_grammar_generator::context_free_grammar_generator() :
|
||||
initialized_(false)
|
||||
{
|
||||
#include "log.hpp"
|
||||
#include "random_new.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
|
||||
}
|
||||
#include <algorithm>
|
||||
|
||||
context_free_grammar_generator::~context_free_grammar_generator()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool context_free_grammar_generator::constructFromString(const std::string &source) {
|
||||
context_free_grammar_generator::context_free_grammar_generator(const std::string& source) :
|
||||
initialized_(false)
|
||||
{
|
||||
const char* reading = source.c_str();
|
||||
nonterminal* current = nullptr;
|
||||
std::vector<std::string>* filled = nullptr;
|
||||
|
@ -53,7 +52,7 @@ bool context_free_grammar_generator::constructFromString(const std::string &sour
|
|||
} else if (*reading == '|') {
|
||||
if (!filled || !current) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced | symbol";
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
filled->push_back(buf);
|
||||
current->possibilities_.push_back(std::vector<std::string>());
|
||||
|
@ -69,7 +68,7 @@ bool context_free_grammar_generator::constructFromString(const std::string &sour
|
|||
if (*reading == '{') {
|
||||
if (!filled) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced { symbol";
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
filled->push_back(buf);
|
||||
buf.clear();
|
||||
|
@ -77,7 +76,7 @@ bool context_free_grammar_generator::constructFromString(const std::string &sour
|
|||
if (*reading == '}') {
|
||||
if (!filled) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced } symbol";
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
filled->push_back(buf);
|
||||
buf.clear();
|
||||
|
@ -88,7 +87,43 @@ bool context_free_grammar_generator::constructFromString(const std::string &sour
|
|||
if (filled) filled->push_back(buf);
|
||||
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
context_free_grammar_generator::context_free_grammar_generator(const std::map<std::string, std::vector<std::string>>& source) :
|
||||
initialized_(false)
|
||||
{
|
||||
for(auto rule : source) {
|
||||
std::string key = rule.first; // Need to do this because utils::strip is mutating
|
||||
key = utils::strip(key);
|
||||
std::string buf;
|
||||
for(std::string str : rule.second) {
|
||||
nonterminals_[key].possibilities_.emplace_back();
|
||||
std::vector<std::string>* filled = &nonterminals_[key].possibilities_.back();
|
||||
// A little code duplication here...
|
||||
for(char c : str) {
|
||||
if (c == '{') {
|
||||
if (!filled) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced { symbol";
|
||||
return;
|
||||
}
|
||||
filled->push_back(buf);
|
||||
buf.clear();
|
||||
}
|
||||
else if (c == '}') {
|
||||
if (!filled) {
|
||||
lg::wml_error() << "[context_free_grammar_generator] Parsing error: misplaced } symbol";
|
||||
return;
|
||||
}
|
||||
filled->push_back('{' + utils::strip(buf));
|
||||
buf.clear();
|
||||
} else buf.push_back(c);
|
||||
}
|
||||
if(!buf.empty()) {
|
||||
filled->push_back(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
std::string context_free_grammar_generator::print_nonterminal(const std::string& name, uint32_t* seed, short seed_pos) const {
|
||||
|
|
|
@ -15,12 +15,14 @@
|
|||
#ifndef CONTEXT_FREE_GRAMMAR_GENERATOR_INCLUDED
|
||||
#define CONTEXT_FREE_GRAMMAR_GENERATOR_INCLUDED
|
||||
|
||||
#include "utils/name_generator.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
class context_free_grammar_generator
|
||||
class context_free_grammar_generator : public name_generator
|
||||
{
|
||||
private:
|
||||
|
||||
|
@ -36,26 +38,27 @@ private:
|
|||
static const short unsigned int seed_size = 20;
|
||||
|
||||
public:
|
||||
/** Default constructor */
|
||||
context_free_grammar_generator();
|
||||
|
||||
/** Initialisation
|
||||
* @param source the definition of the context-free grammar to use
|
||||
* @returns if the operation was successful
|
||||
*/
|
||||
bool constructFromString(const std::string& source);
|
||||
context_free_grammar_generator(const std::string& source);
|
||||
|
||||
/** Initialisation
|
||||
* @param source A map of nonterminals to lists of possibilities
|
||||
*/
|
||||
context_free_grammar_generator(const std::map<std::string, std::vector<std::string>>& source);
|
||||
|
||||
/** Generates a possible word in the grammar set before
|
||||
* @returns the word
|
||||
* @return the word
|
||||
*/
|
||||
std::string generate() const;
|
||||
std::string generate() const override;
|
||||
|
||||
~context_free_grammar_generator();
|
||||
|
||||
/** Checks if the object is initialized
|
||||
* @returns if it is initialized
|
||||
* @return if it is initialized
|
||||
*/
|
||||
bool is_initialized() const {return initialized_; }
|
||||
bool is_valid() const override {return initialized_; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,33 +17,11 @@
|
|||
* Generate race-specific unit-names.
|
||||
*/
|
||||
|
||||
#include "global.hpp"
|
||||
#include "markov_generator.hpp"
|
||||
|
||||
#include "race.hpp"
|
||||
|
||||
#include "log.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "serialization/unicode_cast.hpp"
|
||||
#include "random_new.hpp"
|
||||
|
||||
/// Dummy race used when a race is not yet known.
|
||||
const unit_race unit_race::null_race;
|
||||
/// Standard string id (not translatable) for FEMALE
|
||||
const std::string unit_race::s_female("female");
|
||||
/// Standard string id (not translatable) for MALE
|
||||
const std::string unit_race::s_male("male");
|
||||
|
||||
|
||||
static const config &empty_traits() {
|
||||
static config cfg;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static const config &empty_topics() {
|
||||
static config cfg;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static void add_prefixes(const ucs4::string& str, size_t length, markov_prefix_map& res)
|
||||
{
|
||||
for(size_t i = 0; i <= str.size(); ++i) {
|
||||
|
@ -145,118 +123,15 @@ static ucs4::string markov_generate_name(const markov_prefix_map& prefixes,
|
|||
return originalRes;
|
||||
}
|
||||
|
||||
unit_race::unit_race() :
|
||||
cfg_(),
|
||||
id_(),
|
||||
plural_name_(),
|
||||
description_(),
|
||||
ntraits_(0),
|
||||
chain_size_(0),
|
||||
traits_(empty_traits().child_range("trait")),
|
||||
topics_(empty_topics().child_range("topic")),
|
||||
global_traits_(true),
|
||||
undead_variation_()
|
||||
markov_generator::markov_generator(const std::vector<std::string>& items, size_t chain_size, size_t max_len)
|
||||
: prefixes_(markov_prefixes(items, chain_size))
|
||||
, chain_size_(chain_size)
|
||||
, max_len_(max_len)
|
||||
{
|
||||
name_[MALE] = "";
|
||||
name_[FEMALE] = "";
|
||||
}
|
||||
|
||||
unit_race::unit_race(const config& cfg) :
|
||||
cfg_(cfg),
|
||||
id_(cfg["id"]),
|
||||
plural_name_(cfg["plural_name"].t_str()),
|
||||
description_(cfg["description"].t_str()),
|
||||
ntraits_(cfg["num_traits"]),
|
||||
chain_size_(cfg["markov_chain_size"]),
|
||||
traits_(cfg.child_range("trait")),
|
||||
topics_(cfg.child_range("topic")),
|
||||
global_traits_(!cfg["ignore_global_traits"].to_bool()),
|
||||
undead_variation_(cfg["undead_variation"])
|
||||
|
||||
std::string markov_generator::generate() const
|
||||
{
|
||||
if (id_.empty()) {
|
||||
lg::wml_error() << "[race] '" << cfg["name"] << "' is missing an id field.";
|
||||
}
|
||||
if (plural_name_.empty()) {
|
||||
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()) {
|
||||
name_[MALE] = (cfg["name"]);
|
||||
}
|
||||
name_[FEMALE] = cfg["female_name"];
|
||||
if(name_[FEMALE].empty()) {
|
||||
name_[FEMALE] = (cfg["name"]);
|
||||
}
|
||||
|
||||
if (cfg.has_attribute("male_name_generator")) {
|
||||
name_generator_[MALE].constructFromString(cfg["male_name_generator"]);
|
||||
}
|
||||
if (cfg.has_attribute("female_name_generator")) {
|
||||
name_generator_[FEMALE].constructFromString(cfg["female_name_generator"]);
|
||||
}
|
||||
if (cfg.has_attribute("name_generator")) {
|
||||
if (!name_generator_[MALE].is_initialized()) {
|
||||
name_generator_[MALE].constructFromString(cfg["name_generator"]);
|
||||
}
|
||||
if (!name_generator_[FEMALE].is_initialized()) {
|
||||
name_generator_[FEMALE].constructFromString(cfg["name_generator"]);
|
||||
}
|
||||
}
|
||||
|
||||
if(chain_size_ <= 0)
|
||||
chain_size_ = 2;
|
||||
|
||||
//std::vector<std::string> names = ;
|
||||
next_[MALE] = markov_prefixes(utils::split(cfg["male_names"]), chain_size_);
|
||||
next_[FEMALE] = markov_prefixes(utils::split(cfg["female_names"]), chain_size_);
|
||||
}
|
||||
|
||||
std::string unit_race::generate_name(
|
||||
unit_race::GENDER gender) const
|
||||
{
|
||||
if (name_generator_[gender].is_initialized()) {
|
||||
return name_generator_[gender].generate();
|
||||
}
|
||||
return unicode_cast<utf8::string>(
|
||||
markov_generate_name(next_[gender], chain_size_, 12));
|
||||
}
|
||||
|
||||
bool unit_race::uses_global_traits() const
|
||||
{
|
||||
return global_traits_;
|
||||
}
|
||||
|
||||
const config::const_child_itors &unit_race::additional_traits() const
|
||||
{
|
||||
return traits_;
|
||||
}
|
||||
|
||||
const config::const_child_itors &unit_race::additional_topics() const
|
||||
{
|
||||
return topics_;
|
||||
}
|
||||
|
||||
unsigned int unit_race::num_traits() const { return ntraits_; }
|
||||
|
||||
|
||||
std::string const& gender_string(unit_race::GENDER gender) {
|
||||
switch(gender) {
|
||||
case unit_race::FEMALE:
|
||||
return unit_race::s_female;
|
||||
default:
|
||||
case unit_race::MALE:
|
||||
return unit_race::s_male;
|
||||
}
|
||||
}
|
||||
|
||||
unit_race::GENDER string_gender(const std::string& str, unit_race::GENDER def) {
|
||||
if ( str == unit_race::s_male ) {
|
||||
return unit_race::MALE;
|
||||
} else if ( str == unit_race::s_female ) {
|
||||
return unit_race::FEMALE;
|
||||
}
|
||||
return def;
|
||||
ucs4::string name = markov_generate_name(prefixes_, chain_size_, max_len_);
|
||||
return unicode_cast<utf8::string>(name);
|
||||
}
|
32
src/utils/markov_generator.hpp
Normal file
32
src/utils/markov_generator.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
Copyright (C) 2003 - 2016 by David White <dave@whitevine.net>
|
||||
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 MARKOV_GENERATOR_HPP_INCLUDED
|
||||
#define MARKOV_GENERATOR_HPP_INCLUDED
|
||||
|
||||
#include "serialization/unicode_types.hpp"
|
||||
#include "utils/name_generator.hpp"
|
||||
#include <map>
|
||||
|
||||
typedef std::map<ucs4::string, ucs4::string> markov_prefix_map;
|
||||
|
||||
class markov_generator : public name_generator {
|
||||
markov_prefix_map prefixes_;
|
||||
size_t chain_size_, max_len_;
|
||||
public:
|
||||
markov_generator(const std::vector<std::string>& items, size_t chain_size, size_t max_len);
|
||||
std::string generate() const override;
|
||||
};
|
||||
|
||||
#endif
|
35
src/utils/name_generator.hpp
Normal file
35
src/utils/name_generator.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright (C) 2003 - 2016 by David White <dave@whitevine.net>
|
||||
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_HPP_INCLUDED
|
||||
#define NAME_GENERATOR_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
class name_generator {
|
||||
public:
|
||||
virtual std::string generate() const = 0;
|
||||
virtual bool is_valid() const {return true;}
|
||||
virtual ~name_generator() {}
|
||||
};
|
||||
|
||||
class proxy_name_generator : public name_generator {
|
||||
const name_generator& base;
|
||||
public:
|
||||
proxy_name_generator(const name_generator& b) : base(b) {}
|
||||
std::string generate() const override {return base.generate();}
|
||||
bool is_valid() const override {return base.is_valid();}
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue