Merge pull request #279 from gfgtdf/map_generator_refactor

Map generator refactor

the intentions/plans are:
1) fix the 'single use' cave map generator to work in mp.
we fix this by splitting the cave_map_generator into 
cave_map_generator and cave_map_generator_job from which the later is a temporary object used during generate_scenario/map

2) allow to pass a (platform independent) seed to all map generators, this is not completely implemented yet. I implemented this for the cave_map_generator_job and it was already implemented for the yamg. Is still needs to be implemented for the default_map_generator
This commit is contained in:
gfgtdf 2014-08-26 23:36:58 +02:00
commit 494f2701ae
19 changed files with 149 additions and 150 deletions

View file

@ -951,10 +951,10 @@ set(libwesnoth-game_STAT_SRC
events.cpp
font.cpp
format_time_summary.cpp
generators/cavegen.cpp
generators/cave_map_generator.cpp
generators/map_create.cpp
generators/mapgen.cpp
generators/mapgen_dialog.cpp
generators/map_generator.cpp
generators/default_map_generator.cpp
generators/yamg/ya_mapgen.cpp
generators/yamg/yamg_hex.cpp
generators/yamg/yamg_hexheap.cpp

View file

@ -86,10 +86,10 @@ libwesnoth_sources = Split("""
image_modifications.cpp
joystick.cpp
game_end_exceptions.cpp
generators/cavegen.cpp
generators/cave_map_generator.cpp
generators/map_create.cpp
generators/mapgen.cpp
generators/mapgen_dialog.cpp
generators/map_generator.cpp
generators/default_map_generator.cpp
generators/yamg/ya_mapgen.cpp
generators/yamg/yamg_hex.cpp
generators/yamg/yamg_hexheap.cpp

View file

@ -18,6 +18,7 @@
#include "game_launcher.hpp"
#include "game_display.hpp"
#include "game_preferences.hpp"
#include "generators/map_generator.hpp"
#include "gui/dialogs/campaign_difficulty.hpp"
#include "filesystem.hpp"
#include "formula_string_utils.hpp"
@ -729,11 +730,11 @@ void create_engine::set_current_level(const size_t index)
random_map* current_random_map =
dynamic_cast<random_map*>(&current_level());
generator_.assign(create_map_generator(
generator_.reset(create_map_generator(
current_random_map->generator_data()["map_generation"],
current_random_map->generator_data().child("generator")));
} else {
generator_.assign(NULL);
generator_.reset(NULL);
}
if (current_level_type_ != level::CAMPAIGN &&

View file

@ -16,7 +16,6 @@
#include "config.hpp"
#include "map.hpp"
#include "generators/mapgen.hpp"
#include "depcheck.hpp"
#include "mp_game_settings.hpp"
#include "game_display.hpp"
@ -26,7 +25,7 @@
#include <utility>
class saved_game;
class map_generator;
namespace ng {
class level
{
@ -287,7 +286,7 @@ private:
depcheck::manager dependency_manager_;
util::scoped_ptr<map_generator> generator_;
boost::scoped_ptr<map_generator> generator_;
};
} // end namespace ng

View file

@ -23,6 +23,7 @@
#include "formula_string_utils.hpp"
#include "gettext.hpp"
#include "generators/map_create.hpp"
#include "generators/map_generator.hpp"
#include "map_context.hpp"
#include "editor/action/action.hpp"

View file

@ -18,9 +18,7 @@
#include "editor/map/map_context.hpp"
#include "editor/editor_preferences.hpp"
#include "editor/map/map_fragment.hpp"
#include "generators/mapgen.hpp"
class map_generator;
namespace editor {

View file

@ -19,7 +19,7 @@
#include "global.hpp"
#include "cavegen.hpp"
#include "cave_map_generator.hpp"
#include "log.hpp"
#include "map.hpp"
#include "pathfind/pathfind.hpp"
@ -37,31 +37,17 @@ cave_map_generator::cave_map_generator(const config &cfg) :
village_(t_translation::UNDERGROUND_VILLAGE),
castle_(t_translation::DWARVEN_CASTLE),
keep_(t_translation::DWARVEN_KEEP),
map_(),
starting_positions_(),
chamber_ids_(),
chambers_(),
passages_(),
res_(),
cfg_(cfg ? cfg : config()),
width_(50),
height_(50),
village_density_(0),
flipx_(false),
flipy_(false)
flipx_chance_(cfg_["flipx_chance"]),
flipy_chance_(cfg_["flipy_chance"])
{
width_ = cfg_["map_width"];
height_ = cfg_["map_height"];
village_density_ = cfg_["village_density"];
int r = rand() % 100;
int chance = cfg_["flipx_chance"];
flipx_ = r < chance;
LOG_NG << "flipx: " << r << " < " << chance << " = " << (flipx_ ? "true" : "false") << "\n";
flipy_ = rand() % 100 < cfg_["flipy_chance"];
}
std::string cave_map_generator::config_name() const
@ -69,19 +55,19 @@ std::string cave_map_generator::config_name() const
return "";
}
size_t cave_map_generator::translate_x(size_t x) const
size_t cave_map_generator::cave_map_generator_job::translate_x(size_t x) const
{
if(flipx_) {
x = width_ - x - 1;
x = params.width_ - x - 1;
}
return x;
}
size_t cave_map_generator::translate_y(size_t y) const
size_t cave_map_generator::cave_map_generator_job::translate_y(size_t y) const
{
if(flipy_) {
y = height_ - y - 1;
y = params.height_ - y - 1;
}
return y;
@ -95,15 +81,30 @@ std::string cave_map_generator::create_map()
config cave_map_generator::create_scenario()
{
map_ = t_translation::t_map(width_ + 2 * gamemap::default_border,
t_translation::t_list(height_ + 2 * gamemap::default_border, wall_));
chambers_.clear();
passages_.clear();
cave_map_generator_job job(*this);
return job.res_;
}
res_.clear();
if (const config &settings = cfg_.child("settings")) {
res_ = settings;
cave_map_generator::cave_map_generator_job::cave_map_generator_job(const cave_map_generator& pparams, boost::optional<int> randomseed)
: params(pparams)
, flipx_(false)
, flipy_(false)
, map_(t_translation::t_map(params.width_ + 2 * gamemap::default_border,
t_translation::t_list(params.height_ + 2 * gamemap::default_border, params.wall_)))
, starting_positions_()
, chamber_ids_()
, chambers_()
, passages_()
, res_(params.cfg_.child_or_empty("settings"))
, rng_() //initialises with rand()
{
if(int* seed = randomseed.get_ptr())
{
rng_.seed_random(*seed);
}
std::cerr << "creating random cave with seed:" << rng_.get_random_seed();
flipx_ = rng_.get_next_random() % 100 < params.flipx_chance_;
flipy_ = rng_.get_next_random() % 100 < params.flipy_chance_;
LOG_NG << "creating scenario....\n";
generate_chambers();
@ -118,22 +119,17 @@ config cave_map_generator::create_scenario()
for(std::vector<passage>::const_iterator p = passages_.begin(); p != passages_.end(); ++p) {
place_passage(*p);
}
LOG_NG << "outputting map....\n";
config& map = res_.add_child("map");
map["data"] = t_translation::write_game_map(map_, starting_positions_);
map["usage"] = "map";
map["border_size"] = gamemap::default_border;
LOG_NG << "returning result...\n";
return res_;
}
void cave_map_generator::build_chamber(map_location loc, std::set<map_location>& locs, size_t size, size_t jagged)
void cave_map_generator::cave_map_generator_job::build_chamber(map_location loc, std::set<map_location>& locs, size_t size, size_t jagged)
{
if(size == 0 || locs.count(loc) != 0 || !on_board(loc))
if(size == 0 || locs.count(loc) != 0 || !params.on_board(loc))
return;
locs.insert(loc);
@ -141,25 +137,25 @@ void cave_map_generator::build_chamber(map_location loc, std::set<map_location>&
map_location adj[6];
get_adjacent_tiles(loc,adj);
for(size_t n = 0; n != 6; ++n) {
if((rand() % 100) < (100l - static_cast<long>(jagged))) {
if((rng_.get_next_random() % 100) < (100l - static_cast<long>(jagged))) {
build_chamber(adj[n],locs,size-1,jagged);
}
}
}
void cave_map_generator::generate_chambers()
void cave_map_generator::cave_map_generator_job::generate_chambers()
{
BOOST_FOREACH(const config &ch, cfg_.child_range("chamber"))
BOOST_FOREACH(const config &ch, params.cfg_.child_range("chamber"))
{
// If there is only a chance of the chamber appearing, deal with that here.
if (ch.has_attribute("chance") && (rand() % 100) < ch["chance"].to_int()) {
if (ch.has_attribute("chance") && (rng_.get_next_random() % 100) < ch["chance"].to_int()) {
continue;
}
const std::string &xpos = ch["x"];
const std::string &ypos = ch["y"];
size_t min_xpos = 0, min_ypos = 0, max_xpos = width_, max_ypos = height_;
size_t min_xpos = 0, min_ypos = 0, max_xpos = params.width_, max_ypos = params.height_;
if (!xpos.empty()) {
const std::vector<std::string>& items = utils::split(xpos, '-');
@ -176,9 +172,8 @@ void cave_map_generator::generate_chambers()
max_ypos = atoi(items.back().c_str());
}
}
const size_t x = translate_x(min_xpos + (rand()%(max_xpos-min_xpos)));
const size_t y = translate_y(min_ypos + (rand()%(max_ypos-min_ypos)));
const size_t x = translate_x(min_xpos + (rng_.get_next_random()%(max_xpos-min_xpos)));
const size_t y = translate_y(min_ypos + (rng_.get_next_random()%(max_ypos-min_ypos)));
int chamber_size = ch["size"].to_int(3);
int jagged_edges = ch["jagged"];
@ -213,10 +208,10 @@ void cave_map_generator::generate_chambers()
}
}
void cave_map_generator::place_chamber(const chamber& c)
void cave_map_generator::cave_map_generator_job::place_chamber(const chamber& c)
{
for(std::set<map_location>::const_iterator i = c.locs.begin(); i != c.locs.end(); ++i) {
set_terrain(*i,clear_);
set_terrain(*i,params.clear_);
}
if (c.items == NULL || c.locs.empty()) return;
@ -233,7 +228,7 @@ void cave_map_generator::place_chamber(const chamber& c)
}
if (!it.cfg["same_location_as_previous"].to_bool()) {
index = rand()%c.locs.size();
index = rng_.get_next_random()%c.locs.size();
}
std::string loc_var = it.cfg["store_location_as"];
@ -277,8 +272,9 @@ struct passage_path_calculator : pathfind::cost_calculator
{
passage_path_calculator(const t_translation::t_map& mapdata,
const t_translation::t_terrain & wall,
double laziness, size_t windiness) :
map_(mapdata), wall_(wall), laziness_(laziness), windiness_(windiness)
double laziness, size_t windiness,
rand_rng::simple_rng& rng) :
map_(mapdata), wall_(wall), laziness_(laziness), windiness_(windiness), rng_(rng)
{}
virtual double cost(const map_location& loc, const double so_far) const;
@ -287,6 +283,7 @@ private:
t_translation::t_terrain wall_;
double laziness_;
size_t windiness_;
rand_rng::simple_rng& rng_;
};
double passage_path_calculator::cost(const map_location& loc, const double) const
@ -297,16 +294,16 @@ double passage_path_calculator::cost(const map_location& loc, const double) cons
}
if(windiness_ > 1) {
res *= double(rand()%windiness_);
res *= double(rng_.get_next_random()%windiness_);
}
return res;
}
void cave_map_generator::place_passage(const passage& p)
void cave_map_generator::cave_map_generator_job::place_passage(const passage& p)
{
const std::string& chance = p.cfg["chance"];
if(chance != "" && (rand()%100) < atoi(chance.c_str())) {
if(chance != "" && (rng_.get_next_random()%100) < atoi(chance.c_str())) {
return;
}
@ -314,9 +311,9 @@ void cave_map_generator::place_passage(const passage& p)
int windiness = p.cfg["windiness"];
double laziness = std::max<double>(1.0, p.cfg["laziness"].to_double());
passage_path_calculator calc(map_,wall_,laziness,windiness);
passage_path_calculator calc(map_, params.wall_, laziness, windiness, rng_);
pathfind::plain_route rt = a_star_search(p.src, p.dst, 10000.0, &calc, width_, height_);
pathfind::plain_route rt = a_star_search(p.src, p.dst, 10000.0, &calc, params.width_, params.height_);
int width = std::max<int>(1, p.cfg["width"].to_int());
int jagged = p.cfg["jagged"];
@ -325,31 +322,31 @@ void cave_map_generator::place_passage(const passage& p)
std::set<map_location> locs;
build_chamber(*i,locs,width,jagged);
for(std::set<map_location>::const_iterator j = locs.begin(); j != locs.end(); ++j) {
set_terrain(*j,clear_);
set_terrain(*j, params.clear_);
}
}
}
void cave_map_generator::set_terrain(map_location loc, const t_translation::t_terrain & t)
void cave_map_generator::cave_map_generator_job::set_terrain(map_location loc, const t_translation::t_terrain & t)
{
if (on_board(loc)) {
if (params.on_board(loc)) {
t_translation::t_terrain& c = map_[loc.x + gamemap::default_border][loc.y + gamemap::default_border];
if(c == clear_ || c == wall_ || c == village_) {
if(c == params.clear_ || c == params.wall_ || c == params.village_) {
// Change this terrain.
if ( t == clear_ && rand() % 1000 < village_density_ )
if ( t == params.clear_ && rng_.get_next_random() % 1000 < params.village_density_ )
// Override with a village.
c = village_;
c = params.village_;
else
c = t;
}
}
}
void cave_map_generator::place_castle(int starting_position, const map_location &loc)
void cave_map_generator::cave_map_generator_job::place_castle(int starting_position, const map_location &loc)
{
if (starting_position != -1) {
set_terrain(loc, keep_);
set_terrain(loc, params.keep_);
t_translation::coordinate coord(
loc.x + gamemap::default_border
@ -360,7 +357,7 @@ void cave_map_generator::place_castle(int starting_position, const map_location
map_location adj[6];
get_adjacent_tiles(loc,adj);
for(size_t n = 0; n != 6; ++n) {
set_terrain(adj[n],castle_);
set_terrain(adj[n], params.castle_);
}
}

View file

@ -14,24 +14,22 @@
/** @file */
#ifndef CAVEGEN_HPP_INCLUDED
#define CAVEGEN_HPP_INCLUDED
#ifndef CAVE_MAP_GENERATOR_HPP_INCLUDED
#define CAVE_MAP_GENERATOR_HPP_INCLUDED
#include "config.hpp"
#include "generators/mapgen.hpp"
#include "generators/map_generator.hpp"
#include "simple_rng.hpp"
#include "terrain_translation.hpp"
#include <set>
#include <boost/optional.hpp>
class cave_map_generator : public map_generator
{
public:
cave_map_generator(const config &game_config);
bool allow_user_config() const { return true; }
// This is a pure virtual function in the base class, so must be here
void user_config(display& /* disp*/) { return; }
std::string name() const { return "cave"; }
std::string config_name() const;
@ -40,61 +38,70 @@ public:
config create_scenario();
private:
struct cave_map_generator_job
{
cave_map_generator_job(const cave_map_generator& params, boost::optional<int> randomseed = boost::none);
struct chamber {
chamber() :
center(),
locs(),
items(0)
{
}
struct chamber {
chamber()
: center()
, locs()
, items(0)
{
}
map_location center;
std::set<map_location> locs;
const config *items;
map_location center;
std::set<map_location> locs;
const config *items;
};
struct passage {
passage(map_location s, map_location d, const config& c)
: src(s), dst(d), cfg(c)
{}
map_location src, dst;
config cfg;
};
void generate_chambers();
void build_chamber(map_location loc, std::set<map_location>& locs, size_t size, size_t jagged);
void place_chamber(const chamber& c);
void place_passage(const passage& p);
void set_terrain(map_location loc, const t_translation::t_terrain & t);
void place_castle(int starting_position, const map_location &loc);
size_t translate_x(size_t x) const;
size_t translate_y(size_t y) const;
const cave_map_generator& params;
bool flipx_, flipy_;
t_translation::t_map map_;
std::map<int, t_translation::coordinate> starting_positions_;
std::map<std::string,size_t> chamber_ids_;
std::vector<chamber> chambers_;
std::vector<passage> passages_;
config res_;
rand_rng::simple_rng rng_;
};
struct passage {
passage(map_location s, map_location d, const config& c)
: src(s), dst(d), cfg(c)
{}
map_location src, dst;
config cfg;
};
void generate_chambers();
void build_chamber(map_location loc, std::set<map_location>& locs, size_t size, size_t jagged);
void place_chamber(const chamber& c);
void place_passage(const passage& p);
bool on_board(const map_location& loc) const
{
return loc.x >= 0 && loc.y >= 0 && loc.x < width_ && loc.y < height_;
}
void set_terrain(map_location loc, const t_translation::t_terrain & t);
void place_castle(int starting_position, const map_location &loc);
t_translation::t_terrain wall_, clear_, village_, castle_, keep_;
t_translation::t_map map_;
std::map<int, t_translation::coordinate> starting_positions_;
std::map<std::string,size_t> chamber_ids_;
std::vector<chamber> chambers_;
std::vector<passage> passages_;
config res_;
config cfg_;
int width_, height_, village_density_;
// The scenario may have a chance to flip all x values or y values
// to make the scenario appear all random. This is kept track of here.
bool flipx_, flipy_;
size_t translate_x(size_t x) const;
size_t translate_y(size_t y) const;
int flipx_chance_, flipy_chance_;
};
#endif

View file

@ -16,7 +16,7 @@
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "mapgen_dialog.hpp"
#include "default_map_generator.hpp"
#include "display.hpp"
#include "gettext.hpp"

View file

@ -12,11 +12,11 @@
See the COPYING file for more details.
*/
#ifndef MAPGEN_DIALOG_HPP_INCLUDED
#define MAPGEN_DIALOG_HPP_INCLUDED
#ifndef DEFAULT_MAP_GENERATOR_HPP_INCLUDED
#define DEFAULT_MAP_GENERATOR_HPP_INCLUDED
#include "config.hpp"
#include "generators/mapgen.hpp"
#include "generators/map_generator.hpp"
class default_map_generator : public map_generator
{

View file

@ -15,10 +15,10 @@
#include "global.hpp"
#include "map_create.hpp"
#include "generators/cavegen.hpp"
#include "generators/cave_map_generator.hpp"
#include "generators/yamg/ya_mapgen.hpp"
#include "generators/default_map_generator.hpp"
#include "log.hpp"
#include "mapgen_dialog.hpp"
#include "scoped_resource.hpp"
#include "serialization/string_utils.hpp"

View file

@ -23,7 +23,7 @@
#include "language.hpp"
#include "log.hpp"
#include "map.hpp"
#include "mapgen.hpp"
#include "map_generator.hpp"
#include "pathfind/pathfind.hpp"
#include "pathutils.hpp"
#include "race.hpp"
@ -44,6 +44,17 @@ config map_generator::create_scenario()
res["map_data"] = create_map();
return res;
}
/**
by default we don't allow user configs.
*/
bool map_generator::allow_user_config() const
{
return false;
}
void map_generator::user_config(display& /*disp*/)
{
}
typedef std::vector<std::vector<int> > height_map;
typedef t_translation::t_map terrain_map;

View file

@ -38,17 +38,17 @@ public:
virtual ~map_generator() {}
/**
* Returns true iff the map generator has an interactive screen,
* Returns true if the map generator has an interactive screen,
* which allows the user to modify how the generator behaves.
*/
virtual bool allow_user_config() const = 0;
virtual bool allow_user_config() const;
/**
* Display the interactive screen, which allows the user
* to modify how the generator behaves.
* (This function will not be called if allow_user_config() returns false).
*/
virtual void user_config(display& disp) = 0;
virtual void user_config(display& disp);
/**
* Returns a string identifying the generator by name.

View file

@ -285,18 +285,6 @@ ya_mapgen::ya_mapgen(const config& /*cfg*/) :
endpoints_ = NULL;
}
/**
*** allow_user_config
No UI at this point.
*/
bool ya_mapgen::allow_user_config() const {
return false;
}
void ya_mapgen::user_config(display& /*disp*/) {
return;
}
/**
*** name
Returns generator's name

View file

@ -38,7 +38,7 @@
#ifndef YAMG_STANDALONE
#include "config.hpp"
#include "generators/mapgen.hpp"
#include "generators/map_generator.hpp"
#endif
/**
@ -84,8 +84,6 @@ public:
//----------- Inherited methods from map_generator -----------------
#ifndef YAMG_STANDALONE
bool allow_user_config() const;
void user_config(display& disp);
std::string name() const; // {return "yamg";};
std::string config_name() const; // {return "generator";};
std::string create_map();

View file

@ -21,7 +21,7 @@
#include "gui/widgets/button.hpp"
#include "gui/widgets/label.hpp"
#include "gui/widgets/settings.hpp"
#include "generators/mapgen.hpp"
#include "generators/map_generator.hpp"
#include <boost/bind.hpp>

View file

@ -17,6 +17,7 @@
#include "formula_string_utils.hpp"
#include "game_preferences.hpp"
#include "generators/map_create.hpp"
#include "generators/map_generator.hpp"
#include "gettext.hpp"
#include "gui/dialogs/lobby_main.hpp"
#include "gui/dialogs/message.hpp"

View file

@ -21,7 +21,6 @@
#include "widgets/slider.hpp"
#include "widgets/scrollpane.hpp"
#include "widgets/combo.hpp"
#include "generators/mapgen.hpp"
#include "tooltips.hpp"
#include "mp_options.hpp"
#include "configure_engine.hpp"

View file

@ -22,7 +22,6 @@
#include "multiplayer_ui.hpp"
#include "widgets/slider.hpp"
#include "widgets/combo.hpp"
#include "generators/mapgen.hpp"
#include "tooltips.hpp"
namespace mp {