Separate gui and engine in mp::create.

Some things still need to be moved from gui to engine.
This commit is contained in:
Andrius Silinskas 2013-06-26 21:08:06 +01:00
parent 6e751a6a5f
commit 97559fa5ec
7 changed files with 818 additions and 501 deletions

View file

@ -18970,6 +18970,14 @@
RelativePath="..\..\src\multiplayer_create.hpp"
>
</File>
<File
RelativePath="..\..\src\multiplayer_create_engine.cpp"
>
</File>
<File
RelativePath="..\..\src\multiplayer_create_engine.hpp"
>
</File>
<File
RelativePath="..\..\src\multiplayer_error_codes.hpp"
>

View file

@ -772,6 +772,7 @@ set(wesnoth-main_SRC
multiplayer_configure.cpp
multiplayer_connect.cpp
multiplayer_create.cpp
multiplayer_create_engine.cpp
multiplayer_lobby.cpp
multiplayer_ui.cpp
multiplayer_wait.cpp

View file

@ -440,6 +440,7 @@ wesnoth_sources = Split("""
multiplayer_configure.cpp
multiplayer_connect.cpp
multiplayer_create.cpp
multiplayer_create_engine.cpp
multiplayer_lobby.cpp
multiplayer_ui.cpp
multiplayer_wait.cpp

View file

@ -30,7 +30,6 @@
#include "generators/map_create.hpp"
#include "gui/dialogs/message.hpp"
#include "gui/dialogs/campaign_difficulty.hpp"
#include "gui/dialogs/campaign_selection.hpp"
#include "gui/dialogs/mp_create_game_choose_mods.hpp"
#include "gui/dialogs/mp_create_game_set_password.hpp"
#include "gui/dialogs/transient_message.hpp"
@ -57,56 +56,18 @@ const SDL_Rect null_rect = {0, 0, 0, 0};
namespace mp {
mp_level::mp_level() :
map_data(),
image_label(),
campaign(),
type(SCENARIO)
{
}
void mp_level::reset()
{
map_data = "";
image_label = "";
campaign.clear();
}
void mp_level::set_scenario()
{
reset();
type = SCENARIO;
}
void mp_level::set_campaign()
{
reset();
type = CAMPAIGN;
}
mp_level::TYPE mp_level::get_type() const
{
return type;
}
create::create(game_display& disp, const config &cfg, chat& c, config& gamelist, bool local_players_only) :
ui(disp, _("Create Game"), cfg, c, gamelist),
local_players_only_(local_players_only),
tooltip_manager_(disp.video()),
era_selection_(-1),
level_selection_(-1),
mod_selection_(-1),
user_maps_(),
level_selection_(-1),
era_options_(),
level_options_(),
mod_options_(),
era_descriptions_(),
level_descriptions_(),
mod_descriptions_(),
level_index_(),
eras_menu_(disp.video(), std::vector<std::string>()),
levels_menu_(disp.video(), std::vector<std::string>()),
mods_menu_(disp.video(), std::vector<std::string>()),
@ -129,24 +90,28 @@ create::create(game_display& disp, const config &cfg, chat& c, config& gamelist,
filter_name_(disp.video(), 100, "", true),
image_restorer_(NULL),
image_rect_(null_rect),
map_(),
generator_(NULL),
parameters_(),
mp_level_(),
state_(),
dependency_manager_(cfg, disp.video())
dependency_manager_(cfg, disp.video()),
engine_(level::USER_MAP, parameters_, dependency_manager_)
{
filter_num_players_slider_.set_min(0);
filter_num_players_slider_.set_max(9);
filter_num_players_slider_.set_increment(1);
// Build the list of scenarios to play
DBG_MP << "constructing multiplayer create dialog" << std::endl;
set_levels_menu(true);
const std::vector<std::string>& names = levels_menu_item_names();
levels_menu_.set_items(names);
levels_menu_.set_numeric_keypress_selection(false);
if (size_t(preferences::map()) < names.size()) {
levels_menu_.move_selection(preferences::map());
dependency_manager_.try_scenario_by_index(preferences::map(), true);
}
sync_current_level_with_engine();
// The possible eras to play
BOOST_FOREACH(const config &er, cfg.child_range("era")) {
era_options_.push_back(er["name"]);
@ -185,8 +150,6 @@ create::create(game_display& disp, const config &cfg, chat& c, config& gamelist,
i18n_symbols["login"] = preferences::login();
gamelist_updated();
get_level_image();
}
create::~create()
@ -237,62 +200,48 @@ void create::process_event()
}
if (launch_game_.pressed() || levels_menu_.double_clicked()) {
switch (mp_level_.get_type()) {
case mp_level::SCENARIO: {
if (map_.get() == NULL) {
gui2::show_transient_message(disp_.video(), "",
_("The map is invalid."));
} else {
set_result(CREATE);
return;
if (engine_.current_level().can_launch_game()) {
if (engine_.current_level_type() == level::CAMPAIGN) {
std::string difficulty = select_campaign_difficulty();
if (difficulty == "CANCEL") {
return;
}
engine_.prepare_for_campaign(difficulty);
}
break;
engine_.prepare_for_new_level();
set_result(CREATE);
return;
} else {
gui2::show_transient_message(disp_.video(), "",
_("The level is invalid."));
}
case mp_level::CAMPAIGN: {
if (new_campaign()) {
resources::config_manager->
load_game_config_for_game(state_.classification());
const config& level = game_config().find_child("multiplayer",
"id", mp_level_.campaign["first_scenario"]);
parameters_.scenario_data = level;
set_result(CREATE);
return;
}
break;
}
} // end switch
}
if (switch_levels_menu_.pressed()) {
switch (mp_level_.get_type()) {
case mp_level::SCENARIO: {
mp_level_.set_campaign();
switch_levels_menu_.set_label(_("Switch to maps"));
level_label_.set_text(_("Campaigns to play:"));
break;
}
case mp_level::CAMPAIGN: {
mp_level_.set_scenario();
if (engine_.current_level_type() == level::CAMPAIGN) {
switch_levels_menu_.set_label(_("Switch to campaigns"));
level_label_.set_text(_("Maps to play:"));
break;
}
} // end switch
engine_.set_current_level_type(level::USER_MAP);
sync_current_level_with_engine();
} else {
switch_levels_menu_.set_label(_("Switch to maps"));
level_label_.set_text(_("Campaigns to play:"));
set_levels_menu();
engine_.set_current_level_type(level::CAMPAIGN);
sync_current_level_with_engine();
}
levels_menu_.set_items(levels_menu_item_names());
level_selection_ = -1;
}
if (load_game_.pressed()) {
set_level_data(SAVED_GAME, 0);
engine_.prepare_for_saved_game();
set_result(LOAD_GAME);
return;
@ -311,63 +260,36 @@ void create::process_event()
level_selection_ = levels_menu_.selection();
if (level_changed) {
description_.set_text(level_descriptions_[level_selection_]);
dependency_manager_.try_scenario_by_index(level_selection_);
sync_current_level_with_engine();
description_.set_text(engine_.current_level().description());
dependency_manager_.try_scenario_by_index(levels_menu_.selection());
synchronize_selections();
}
if(level_changed) {
generator_.assign(NULL);
tooltips::clear_tooltips(image_rect_);
const size_t select = size_t(levels_menu_.selection());
engine_.init_current_level_data();
switch (mp_level_.get_type()) {
case mp_level::SCENARIO: {
if (select < user_maps_.size()) {
set_level_data(GENERIC_MULTIPLAYER, select);
} else if(select >= user_maps_.size()) {
if (set_level_data(MULTIPLAYER, select)) {
// If the map should be randomly generated.
if (!parameters_.scenario_data["map_generation"].empty()) {
generator_.assign(create_map_generator(
parameters_.scenario_data["map_generation"],
parameters_.scenario_data.child("generator")));
}
if (!parameters_.scenario_data["description"].empty()) {
tooltips::add_tooltip(image_rect_,
parameters_.scenario_data["description"], "", false);
}
}
}
break;
if (!engine_.current_level().description().empty()) {
tooltips::add_tooltip(image_rect_,
engine_.current_level().description(), "", false);
}
case mp_level::CAMPAIGN: {
set_level_data(CAMPAIGN, select);
if (!mp_level_.campaign["description"].empty()) {
tooltips::add_tooltip(image_rect_,
mp_level_.campaign["description"], "", false);
}
break;
}
} // end switch
}
if(generator_ != NULL && generator_->allow_user_config() &&
generator_settings_.pressed()) {
generator_->user_config(disp_);
if (engine_.generator_assigned() && generator_settings_.pressed()) {
engine_.generator_user_config(disp_);
level_changed = true;
}
if(generator_ != NULL && (level_changed || regenerate_map_.pressed())) {
if(engine_.generator_assigned() &&
(level_changed || regenerate_map_.pressed())) {
const cursor::setter cursor_setter(cursor::WAIT);
cursor::setter cur(cursor::WAIT);
set_level_data(GENERATED_MAP, 0);
engine_.init_generated_level_data();
if (!parameters_.scenario_data["error_message"].empty())
gui2::show_message(disp().video(), "map generation error",
@ -379,42 +301,25 @@ void create::process_event()
if(level_changed) {
parameters_.hash = parameters_.scenario_data.hash();
bool enable_launch_game = true;
std::stringstream players;
std::stringstream map_size;
get_level_image();
engine_.current_level().set_metadata();
draw_level_image();
switch (mp_level_.get_type()) {
case mp_level::SCENARIO: {
// If there are less sides in the configuration than there are
// starting positions, then generate the additional sides
const int map_positions = map_.get() != NULL ?
map_->num_valid_starting_positions() : 0;
set_level_sides(map_positions);
switch (engine_.current_level_type()) {
case level::SCENARIO:
case level::USER_MAP: {
scenario* current_scenario =
dynamic_cast<scenario*>(&engine_.current_level());
if(map_.get() != NULL) {
int nsides = 0;
BOOST_FOREACH(const config &k,
parameters_.scenario_data.child_range("side")) {
if (k["allow_player"].to_bool(true)) ++nsides;
}
players << _("Players: ") << nsides;
map_size << _("Size: ") << map_.get()->w() <<
utils::unicode_multiplication_sign << map_.get()->h();
} else {
players << _("Error");
map_size << "";
}
enable_launch_game = (map_.get() != NULL);
players << _("Players: ") << current_scenario->num_players();
map_size << _("Size: ") << current_scenario->map_size();
break;
}
case mp_level::CAMPAIGN: {
case level::CAMPAIGN: {
//TODO: add a way to determine
// the information about number of players for mp campaigns.
@ -425,9 +330,9 @@ void create::process_event()
map_size_label_.set_text(map_size.str());
num_players_label_.set_text(players.str());
launch_game_.enable(enable_launch_game);
generator_settings_.enable(generator_ != NULL);
regenerate_map_.enable(generator_ != NULL);
launch_game_.enable(engine_.current_level().can_launch_game());
generator_settings_.enable(engine_.generator_assigned());
regenerate_map_.enable(engine_.generator_assigned());
}
bool mod_selection_changed = mod_selection_ != mods_menu_.selection();
@ -438,6 +343,101 @@ void create::process_event()
}
}
void create::sync_current_level_with_engine()
{
if (engine_.current_level_type() == level::CAMPAIGN) {
engine_.set_current_level_index(levels_menu_.selection());
} else if ((size_t)levels_menu_.selection() < engine_.user_maps_count()) {
engine_.set_current_level_type(level::USER_MAP);
engine_.set_current_level_index(levels_menu_.selection());
} else {
engine_.set_current_level_type(level::SCENARIO);
engine_.set_current_level_index(levels_menu_.selection()
- engine_.user_maps_count());
}
}
void create::synchronize_selections()
{
DBG_MP << "Synchronizing with the dependency manager" << std::endl;
if (era_selection_ != dependency_manager_.get_era_index()) {
eras_menu_.move_selection(dependency_manager_.get_era_index());
process_event();
}
if (level_selection_ != dependency_manager_.get_scenario_index()) {
levels_menu_.move_selection(dependency_manager_.get_scenario_index());
process_event();
}
parameters_.active_mods = dependency_manager_.get_modifications();
}
std::vector<std::string> create::levels_menu_item_names() const
{
switch (engine_.current_level_type()) {
case level::SCENARIO:
case level::USER_MAP: {
const std::vector<std::string>& scenarios =
engine_.levels_menu_item_names(level::SCENARIO);
const std::vector<std::string>& user_maps =
engine_.levels_menu_item_names(level::USER_MAP);
std::vector<std::string> names;
names.reserve(scenarios.size() + user_maps.size());
names.insert(names.end(), user_maps.begin(), user_maps.end());
names.insert(names.end(), scenarios.begin(), scenarios.end());
return names;
}
case level::CAMPAIGN:
default: {
return engine_.levels_menu_item_names(level::CAMPAIGN);
}
} // end switch
}
void create::draw_level_image() const
{
boost::scoped_ptr<surface> image(
engine_.current_level().create_image_surface(image_rect_));
SDL_Color back_color = {0,0,0,255};
draw_centered_on_background(*image, image_rect_, back_color,
video().getSurface());
}
std::string create::select_campaign_difficulty()
{
const std::string difficulty_descriptions =
engine_.current_level().data()["difficulty_descriptions"];
std::vector<std::string> difficulty_options =
utils::split(difficulty_descriptions, ';');
const std::vector<std::string> difficulties =
utils::split(engine_.current_level().data()["difficulties"]);
if(difficulties.empty() == false) {
int difficulty = 0;
if(difficulty_options.size() != difficulties.size()) {
difficulty_options.resize(difficulties.size());
std::copy(difficulties.begin(), difficulties.end(),
difficulty_options.begin());
}
gui2::tcampaign_difficulty dlg(difficulty_options);
dlg.show(disp().video());
if(dlg.selected_index() == -1) {
return "CANCEL";
}
difficulty = dlg.selected_index();
return difficulties[difficulty];
}
return "";
}
void create::hide_children(bool hide)
{
DBG_MP << (hide ? "hiding" : "showing" ) << " children widgets" << std::endl;
@ -476,6 +476,7 @@ void create::hide_children(bool hide)
} else {
image_restorer_.assign(new surface_restorer(&video(), image_rect_));
engine_.current_level().set_metadata();
draw_level_image();
}
}
@ -562,10 +563,9 @@ void create::layout_children(const SDL_Rect& rect)
levels_menu_.set_location(xpos, ypos);
// Menu dimensions are only updated when items are set. So do this now.
int levelsel = levels_menu_.selection();
levels_menu_.set_items(level_options_);
levels_menu_.set_items(levels_menu_item_names());
levels_menu_.move_selection(levelsel);
//Fourth column: eras & mods menu
ypos = ypos_columntop;
xpos += menu_width + column_border_size;
@ -604,287 +604,6 @@ void create::layout_children(const SDL_Rect& rect)
gui::ButtonHPadding, ca.y + ca.h - left_button->height());
}
void create::get_level_image()
{
switch (mp_level_.get_type()) {
case mp_level::SCENARIO: {
const std::string& map_data = parameters_.scenario_data["map_data"];
if ((mp_level_.map_data != map_data) || (mp_level_.map_data == "")) {
try {
map_.reset(new gamemap(game_config(), map_data));
} catch(incorrect_map_format_error& e) {
ERR_CF << "map could not be loaded: " << e.message << '\n';
tooltips::clear_tooltips(image_rect_);
tooltips::add_tooltip(image_rect_,e.message);
} catch(twml_exception& e) {
ERR_CF << "map could not be loaded: " << e.dev_message << '\n';
}
mp_level_.map_data = map_data;
}
break;
}
case mp_level::CAMPAIGN: {
mp_level_.image_label = mp_level_.campaign["image"].str();
break;
}
} // end switch
}
void create::draw_level_image()
{
boost::scoped_ptr<surface> image;
switch (mp_level_.get_type()) {
case mp_level::SCENARIO: {
if (map_.get() != NULL) {
image.reset(new surface(image::getMinimap(image_rect_.w,
image_rect_.h, *map_, 0)));
}
break;
}
case mp_level::CAMPAIGN: {
surface campaign_image(
image::get_image(image::locator(mp_level_.image_label)));
image.reset(new surface(scale_surface(campaign_image, image_rect_.w,
image_rect_.h)));
break;
}
} // end switch
SDL_Color back_color = {0,0,0,255};
draw_centered_on_background(*image, image_rect_, back_color, video().getSurface());
}
bool create::set_level_data(SET_LEVEL set_level, const int select)
{
switch (set_level) {
case GENERIC_MULTIPLAYER: {
parameters_.saved_game = false;
if (const config &generic_multiplayer =
game_config().child("generic_multiplayer")) {
parameters_.scenario_data = generic_multiplayer;
parameters_.scenario_data["map_data"] =
read_map(user_maps_[select]);
}
break;
}
case MULTIPLAYER: {
parameters_.saved_game = false;
size_t index = select - user_maps_.size();
assert(index < level_index_.size());
index = level_index_[index];
config::const_child_itors levels =
game_config().child_range("multiplayer");
for (; index > 0; --index) {
if (levels.first == levels.second) break;
++levels.first;
}
if (levels.first != levels.second)
{
const config &level = *levels.first;
parameters_.scenario_data = level;
std::string map_data = level["map_data"];
if (map_data.empty() && !level["map"].empty()) {
map_data = read_map(level["map"]);
}
} else {
return false;
}
break;
}
case SAVED_GAME: {
parameters_.scenario_data.clear();
parameters_.saved_game = true;
break;
}
case GENERATED_MAP: {
parameters_.scenario_data =
generator_->create_scenario(std::vector<std::string>());
// Set the scenario to have placing of sides
// based on the terrain they prefer
parameters_.scenario_data["modify_placing"] = "true";
break;
}
case CAMPAIGN: {
parameters_.saved_game = false;
size_t index = select;
assert(index < level_index_.size());
index = level_index_[index];
config::const_child_itors levels =
game_config().child_range("campaign");
for (; index > 0; --index) {
if (levels.first == levels.second) break;
++levels.first;
}
if (levels.first != levels.second)
{
const config &level = *levels.first;
mp_level_.campaign = level;
}
break;
}
} // end switch
return true;
}
void create::set_level_sides(const int map_positions)
{
for (int pos = parameters_.scenario_data.child_count("side");
pos < map_positions; ++pos) {
config& side = parameters_.scenario_data.add_child("side");
side["side"] = pos + 1;
side["team_name"] = pos + 1;
side["canrecruit"] = true;
side["controller"] = "human";
}
}
bool create::new_campaign()
{
state_ = game_state();
state_.classification().campaign_type = "multiplayer";
const std::string difficulty_descriptions =
mp_level_.campaign["difficulty_descriptions"];
std::vector<std::string> difficulty_options =
utils::split(difficulty_descriptions, ';');
const std::vector<std::string> difficulties =
utils::split(mp_level_.campaign["difficulties"]);
if(difficulties.empty() == false) {
int difficulty = 0;
if(difficulty_options.size() != difficulties.size()) {
difficulty_options.resize(difficulties.size());
std::copy(difficulties.begin(),difficulties.end(),difficulty_options.begin());
}
gui2::tcampaign_difficulty dlg(difficulty_options);
dlg.show(disp().video());
if(dlg.selected_index() == -1) {
return false;
}
difficulty = dlg.selected_index();
state_.classification().difficulty = difficulties[difficulty];
}
state_.classification().campaign_define =
mp_level_.campaign["define"].str();
state_.classification().campaign_xtra_defines =
utils::split(mp_level_.campaign["extra_defines"]);
return true;
}
void create::synchronize_selections()
{
DBG_MP << "Synchronizing with the dependency manager" << std::endl;
if (era_selection_ != dependency_manager_.get_era_index()) {
eras_menu_.move_selection(dependency_manager_.get_era_index());
process_event();
}
if (level_selection_ != dependency_manager_.get_scenario_index()) {
levels_menu_.move_selection(dependency_manager_.get_scenario_index());
process_event();
}
parameters_.active_mods = dependency_manager_.get_modifications();
}
void create::set_levels_menu(const bool init_dep_check)
{
level_options_.clear();
level_descriptions_.clear();
level_index_.clear();
user_maps_.clear();
std::string markup_txt = "`~";
std::string help_sep = " ";
help_sep[0] = HELP_STRING_SEPARATOR;
std::string menu_help_str;
switch (mp_level_.get_type()) {
case mp_level::SCENARIO: {
// User maps
get_files_in_dir(get_user_data_dir() + "/editor/maps",&user_maps_,NULL,FILE_NAME_ONLY);
size_t i = 0;
for(i = 0; i < user_maps_.size(); i++)
{
menu_help_str = help_sep + user_maps_[i];
level_options_.push_back(user_maps_[i] + menu_help_str);
level_descriptions_.push_back(_("User made map"));
if (init_dep_check) {
// Since user maps are treated as scenarios,
// some dependency info is required
config depinfo;
depinfo["id"] = user_maps_[i];
depinfo["name"] = user_maps_[i];
dependency_manager_.insert_element(depcheck::SCENARIO, depinfo, i);
}
}
// Standard maps
i = 0;
BOOST_FOREACH(const config &j, game_config().child_range("multiplayer"))
{
if (j["allow_new_game"].to_bool(true))
{
std::string name = j["name"];
menu_help_str = help_sep + name;
level_options_.push_back(name + menu_help_str);
level_descriptions_.push_back(j["description"]);
level_index_.push_back(i);
}
++i;
}
break;
}
case mp_level::CAMPAIGN: {
// Campaigns
size_t i = 0;
BOOST_FOREACH(const config &j, game_config().child_range("campaign"))
{
std::string name = j["name"];
menu_help_str = help_sep + name;
level_options_.push_back(name + menu_help_str);
level_descriptions_.push_back(j["description"]);
level_index_.push_back(i);
++i;
}
break;
}
} // end switch
// Create the scenarios menu
levels_menu_.set_items(level_options_);
if (size_t(preferences::map()) < level_options_.size()) {
levels_menu_.move_selection(preferences::map());
dependency_manager_.try_scenario_by_index(preferences::map(), true);
}
}
} // namespace mp

View file

@ -17,9 +17,9 @@
#ifndef MULTIPLAYER_CREATE_HPP_INCLUDED
#define MULTIPLAYER_CREATE_HPP_INCLUDED
#include "gamestatus.hpp"
#include "mp_depcheck.hpp"
#include "mp_game_settings.hpp"
#include "multiplayer_create_engine.hpp"
#include "multiplayer_ui.hpp"
#include "widgets/slider.hpp"
#include "widgets/combo.hpp"
@ -28,27 +28,6 @@
namespace mp {
struct mp_level
{
public:
mp_level();
void reset();
void set_scenario();
void set_campaign();
enum TYPE { SCENARIO, CAMPAIGN };
TYPE get_type() const;
std::string map_data;
std::string image_label;
config campaign;
private:
TYPE type;
};
class create : public mp::ui
{
public:
@ -63,46 +42,28 @@ protected:
virtual void hide_children(bool hide=true);
private:
void get_level_image();
void draw_level_image();
void sync_current_level_with_engine();
enum SET_LEVEL {
GENERIC_MULTIPLAYER,
MULTIPLAYER,
SAVED_GAME,
GENERATED_MAP,
CAMPAIGN
};
bool set_level_data(SET_LEVEL set_level, const int select);
void set_level_sides(const int map_positions);
bool new_campaign();
void set_levels_menu(const bool init_dep_check = false);
void synchronize_selections();
std::vector<std::string> levels_menu_item_names() const;
void draw_level_image() const;
std::string select_campaign_difficulty();
bool local_players_only_;
tooltips::manager tooltip_manager_;
int era_selection_;
int level_selection_;
int mod_selection_;
int level_selection_;
std::vector<std::string> user_maps_;
std::vector<std::string> era_options_;
std::vector<std::string> level_options_;
std::vector<std::string> mod_options_;
std::vector<std::string> era_descriptions_;
std::vector<std::string> level_descriptions_;
std::vector<std::string> mod_descriptions_;
/**
* Due to maps not available the index of the selected map and mp scenarios
* is not 1:1 so we use a lookup table.
*/
std::vector<size_t> level_index_;
gui::menu eras_menu_;
gui::menu levels_menu_;
gui::menu mods_menu_;
@ -131,16 +92,11 @@ private:
util::scoped_ptr<surface_restorer> image_restorer_;
SDL_Rect image_rect_;
boost::scoped_ptr<gamemap> map_;
util::scoped_ptr<map_generator> generator_;
mp_game_settings parameters_;
mp_level mp_level_;
game_state state_;
depcheck::manager dependency_manager_;
create_engine engine_;
};
} // end namespace mp

View file

@ -0,0 +1,456 @@
/*
Copyright (C) 2013 by Andrius Silinskas <silinskas.andrius@gmail.com>
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 "multiplayer_create_engine.hpp"
#include "game_config_manager.hpp"
#include "filesystem.hpp"
#include "formula_string_utils.hpp"
#include "log.hpp"
#include "generators/map_create.hpp"
#include "map_exception.hpp"
#include "minimap.hpp"
#include "wml_separators.hpp"
#include "wml_exception.hpp"
#include <boost/foreach.hpp>
#include <sstream>
static lg::log_domain log_config("config");
#define ERR_CF LOG_STREAM(err, log_config)
static lg::log_domain log_mp_create("mp/create");
#define DBG_MP LOG_STREAM(debug, log_mp_create)
namespace mp {
level::level(const config& data) :
data_(data)
{
}
std::string level::description() const
{
return data_["description"];
}
std::string level::name() const
{
return data_["name"];
}
void level::set_data(const config& data)
{
data_ = data;
}
const config& level::data() const
{
return data_;
}
scenario::scenario(const config& data) :
level(data),
map_(),
num_players_(0)
{
}
scenario::~scenario()
{
}
bool scenario::can_launch_game() const
{
return map_.get() != NULL;
}
surface* scenario::create_image_surface(const SDL_Rect& image_rect)
{
surface* minimap = NULL;
if (map_.get() != NULL) {
minimap = new surface(image::getMinimap(image_rect.w,
image_rect.h, *map_, 0));
}
return minimap;
}
void scenario::set_metadata()
{
const std::string& map_data = data_["map_data"];
try {
map_.reset(new gamemap(resources::config_manager->game_config(),
map_data));
} catch(incorrect_map_format_error& e) {
ERR_CF << "map could not be loaded: " << e.message << '\n';
} catch(twml_exception& e) {
ERR_CF << "map could not be loaded: " << e.dev_message << '\n';
}
set_sides();
}
int scenario::num_players() const
{
return num_players_;
}
std::string scenario::map_size() const
{
std::stringstream map_size;
map_size << map_.get()->w();
map_size << utils::unicode_multiplication_sign;
map_size << map_.get()->h();
return map_size.str();
}
void scenario::set_sides()
{
if (map_.get() != NULL) {
// If there are less sides in the configuration than there are
// starting positions, then generate the additional sides
const int map_positions = map_->num_valid_starting_positions();
for (int pos = data_.child_count("side");
pos < map_positions; ++pos) {
config& side = data_.add_child("side");
side["side"] = pos + 1;
side["team_name"] = pos + 1;
side["canrecruit"] = true;
side["controller"] = "human";
}
num_players_ = 0;
BOOST_FOREACH(const config &scenario, data_.child_range("side")) {
if (scenario["allow_player"].to_bool(true)) {
++num_players_;
}
}
}
}
user_map::user_map(const std::string& name) :
scenario(config()),
name_(name)
{
}
user_map::~user_map()
{
}
std::string user_map::description() const
{
return _("User made map");
}
std::string user_map::name() const
{
return name_;
}
campaign::campaign(const config& data) :
level(data),
image_label_()
{
}
campaign::~campaign()
{
}
bool campaign::can_launch_game() const
{
return !data_.empty();
}
surface* campaign::create_image_surface(const SDL_Rect& image_rect)
{
surface temp_image(
image::get_image(image::locator(image_label_)));
surface* campaign_image = new surface(scale_surface(temp_image,
image_rect.w, image_rect.h));
return campaign_image;
}
void campaign::set_metadata()
{
image_label_ = data_["image"].str();
}
create_engine::create_engine(level::TYPE current_level_type,
mp_game_settings& parameters, depcheck::manager& dependency_manager) :
parameters_(parameters),
dependency_manager_(dependency_manager),
current_level_type_(current_level_type),
current_level_index_(0),
scenarios_(),
user_maps_(),
campaigns_(),
user_map_names_(),
generator_(NULL)
{
get_files_in_dir(get_user_data_dir() + "/editor/maps", &user_map_names_,
NULL, FILE_NAME_ONLY);
init_all_levels();
parameters_.saved_game = false;
}
create_engine::~create_engine()
{
}
void create_engine::init_current_level_data()
{
generator_.assign(NULL);
config const* level = NULL;
switch (current_level_type_) {
case level::SCENARIO: {
level = find_selected_level("multiplayer");
break;
}
case level::USER_MAP: {
if (const config &generic_multiplayer =
resources::config_manager->game_config().child(
"generic_multiplayer")) {
config data = generic_multiplayer;
data["map_data"] =
read_map(user_map_names_[current_level_index_]);
current_level().set_data(data);
}
break;
}
case level::CAMPAIGN: {
level = find_selected_level("campaign");
break;
}
} // end switch
if (level != NULL) {
current_level().set_data(*level);
}
}
void create_engine::init_generated_level_data()
{
config data = generator_->create_scenario(std::vector<std::string>());
// Set the scenario to have placing of sides
// based on the terrain they prefer
data["modify_placing"] = "true";
current_level().set_data(data);
}
void create_engine::prepare_for_new_level()
{
parameters_.scenario_data = current_level().data();
}
void create_engine::prepare_for_campaign(const std::string& difficulty)
{
game_state state = game_state();
state.classification().campaign_type = "multiplayer";
if (difficulty != "") {
state.classification().difficulty = difficulty;
}
state.classification().campaign_define =
current_level().data()["define"].str();
state.classification().campaign_xtra_defines =
utils::split(current_level().data()["extra_defines"]);
resources::config_manager->
load_game_config_for_game(state.classification());
current_level().set_data(
resources::config_manager->game_config().find_child("multiplayer",
"id", current_level().data()["first_scenario"]));
}
void create_engine::prepare_for_saved_game()
{
parameters_.saved_game = true;
parameters_.scenario_data.clear();
}
std::vector<std::string> create_engine::levels_menu_item_names(
const level::TYPE type) const
{
std::vector<std::string> menu_names;
switch (type) {
case level::SCENARIO: {
BOOST_FOREACH(level_ptr level, scenarios_) {
menu_names.push_back(level->name() + HELP_STRING_SEPARATOR +
level->name());
}
break;
}
case level::USER_MAP: {
BOOST_FOREACH(level_ptr level, user_maps_) {
menu_names.push_back(level->name() + HELP_STRING_SEPARATOR +
level->name());
}
break;
}
case level::CAMPAIGN: {
BOOST_FOREACH(level_ptr level, campaigns_) {
menu_names.push_back(level->name() + HELP_STRING_SEPARATOR +
level->name());
}
break;
}
} // end switch
return menu_names;
}
level& create_engine::current_level() const
{
switch (current_level_type_) {
case level::SCENARIO: {
return *scenarios_[current_level_index_];
}
case level::USER_MAP: {
return *user_maps_[current_level_index_];
}
case level::CAMPAIGN:
default: {
return *campaigns_[current_level_index_];
}
} // end switch
}
void create_engine::set_current_level_type(const level::TYPE type)
{
current_level_type_ = type;
}
level::TYPE create_engine::current_level_type() const
{
return current_level_type_;
}
void create_engine::set_current_level_index(const size_t index)
{
current_level_index_ = index;
}
size_t create_engine::current_level_index() const
{
return current_level_index_;
}
size_t create_engine::user_maps_count() const
{
return user_maps_.size();
}
bool create_engine::generator_assigned() const
{
return generator_ != NULL;
}
void create_engine::generator_user_config(display& disp)
{
generator_->user_config(disp);
}
void create_engine::init_all_levels()
{
// User maps.
for(size_t i = 0; i < user_map_names_.size(); i++)
{
user_map_ptr new_user_map(new user_map(user_map_names_[i]));
user_maps_.push_back(new_user_map);
// Since user maps are treated as scenarios,
// some dependency info is required
config depinfo;
depinfo["id"] = user_map_names_[i];
depinfo["name"] = user_map_names_[i];
dependency_manager_.insert_element(depcheck::SCENARIO, depinfo, i);
}
// Stand-alone scenarios.
BOOST_FOREACH(const config &data,
resources::config_manager->game_config().child_range("multiplayer"))
{
if (data["allow_new_game"].to_bool(true))
{
std::string name = data["name"];
scenario_ptr new_scenario(new scenario(data));
scenarios_.push_back(new_scenario);
}
}
// Campaigns.
BOOST_FOREACH(const config &data,
resources::config_manager->game_config().child_range("campaign"))
{
std::string name = data["name"];
campaign_ptr new_campaign(new campaign(data));
campaigns_.push_back(new_campaign);
}
}
config const* create_engine::find_selected_level(const std::string& level_type)
{
size_t index = current_level_index_;
config::const_child_itors levels =
resources::config_manager->game_config().child_range(level_type);
for (; index > 0; --index) {
if (levels.first == levels.second) {
break;
}
++levels.first;
}
if (levels.first != levels.second)
{
const config &level = *levels.first;
// If the map should be randomly generated.
if (!level["map_generation"].empty()) {
generator_.assign(create_map_generator(
level["map_generation"],
level.child("generator")));
}
return &level;
}
return NULL;
}
} // end namespace mp

View file

@ -0,0 +1,176 @@
/*
Copyright (C) 2013 by Andrius Silinskas <silinskas.andrius@gmail.com>
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 MULTIPLAYER_CREATE_ENGINE_HPP_INCLUDED
#define MULTIPLAYER_CREATE_ENGINE_HPP_INCLUDED
#include "config.hpp"
#include "map.hpp"
#include "generators/mapgen.hpp"
#include "mp_depcheck.hpp"
#include "mp_game_settings.hpp"
#include <boost/scoped_ptr.hpp>
#include <string>
namespace mp {
class level
{
public:
level(const config& data);
virtual ~level() {};
enum TYPE { SCENARIO, USER_MAP, CAMPAIGN };
virtual bool can_launch_game() const = 0;
virtual surface* create_image_surface(const SDL_Rect& image_rect) = 0;
virtual void set_metadata() = 0;
virtual std::string name() const;
virtual std::string description() const;
void set_data(const config& data);
const config& data() const;
protected:
config data_;
private:
level(const level&);
void operator=(const level&);
};
class scenario : public level
{
public:
scenario(const config& data);
~scenario();
bool can_launch_game() const;
surface* create_image_surface(const SDL_Rect& image_rect);
void set_metadata();
int num_players() const;
std::string map_size() const;
private:
scenario(const scenario&);
void operator=(const scenario&);
void set_sides();
boost::scoped_ptr<gamemap> map_;
int num_players_;
};
class user_map : public scenario
{
public:
user_map(const std::string& name);
~user_map();
std::string name() const;
std::string description() const;
private:
user_map(const user_map&);
void operator=(const user_map&);
std::string name_;
};
class campaign : public level
{
public:
campaign(const config& data);
~campaign();
bool can_launch_game() const;
surface* create_image_surface(const SDL_Rect& image_rect);
void set_metadata();
private:
campaign(const campaign&);
void operator=(const campaign&);
std::string image_label_;
};
class create_engine
{
public:
create_engine(level::TYPE current_level_type, mp_game_settings& parameters,
depcheck::manager& dependency_manager);
~create_engine();
typedef boost::shared_ptr<level> level_ptr;
typedef boost::shared_ptr<scenario> scenario_ptr;
typedef boost::shared_ptr<user_map> user_map_ptr;
typedef boost::shared_ptr<campaign> campaign_ptr;
void init_current_level_data();
void init_generated_level_data();
void prepare_for_new_level();
void prepare_for_campaign(const std::string& difficulty);
void prepare_for_saved_game();
std::vector<std::string>
levels_menu_item_names(const level::TYPE type) const;
level& current_level() const;
void set_current_level_type(const level::TYPE);
level::TYPE current_level_type() const;
void set_current_level_index(const size_t index);
size_t current_level_index() const;
size_t user_maps_count() const;
bool generator_assigned() const;
void generator_user_config(display& disp);
private:
create_engine(const create_engine&);
void operator=(const create_engine&);
void init_all_levels();
config const* find_selected_level(const std::string& level_type);
mp_game_settings& parameters_;
depcheck::manager& dependency_manager_;
level::TYPE current_level_type_;
size_t current_level_index_;
std::vector<scenario_ptr> scenarios_;
std::vector<user_map_ptr> user_maps_;
std::vector<campaign_ptr> campaigns_;
std::vector<std::string> user_map_names_;
util::scoped_ptr<map_generator> generator_;
};
} // end namespace mp
#endif