Added some missing files.

This commit is contained in:
Philippe Plantier 2005-02-20 22:46:38 +00:00
parent 9283ba2423
commit 9ad4a96b50
4 changed files with 1000 additions and 0 deletions

436
src/multiplayer_create.cpp Normal file
View file

@ -0,0 +1,436 @@
/* $Id$ */
/*
Copyright (C)
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "show_dialog.hpp"
#include "multiplayer_create.hpp"
#include "filesystem.hpp"
#include "preferences.hpp"
namespace {
const SDL_Rect null_rect = {0, 0, 0, 0};
}
namespace mp {
create::create(display& disp, const config &cfg, chat& c, config& gamelist) :
ui(disp, cfg, c, gamelist),
map_selection_(-1),
maps_menu_(disp, std::vector<std::string>()),
turns_slider_(disp),
turns_label_(disp, "", font::SIZE_SMALL, font::GOOD_COLOUR),
village_gold_slider_(disp),
village_gold_label_(disp, "", font::SIZE_SMALL, font::GOOD_COLOUR),
xp_modifier_slider_(disp),
xp_modifier_label_(disp, "", font::SIZE_SMALL, font::GOOD_COLOUR),
name_entry_label_(disp, _("Name of game") + std::string(":"), font::SIZE_SMALL, font::GOOD_COLOUR),
num_players_label_(disp, "", font::SIZE_SMALL, font::GOOD_COLOUR),
era_label_(disp, _("Era") + std::string(":"), font::SIZE_SMALL, font::GOOD_COLOUR),
map_label_(disp, _("Map to play") + std::string(":"), font::SIZE_SMALL, font::GOOD_COLOUR),
fog_game_(disp, _("Fog Of War"), gui::button::TYPE_CHECK),
shroud_game_(disp, _("Shroud"), gui::button::TYPE_CHECK),
observers_game_(disp, _("Observers"), gui::button::TYPE_CHECK),
cancel_game_(disp, _("Cancel")),
launch_game_(disp, _("OK")),
regenerate_map_(disp, _("Regenerate")),
generator_settings_(disp, _("Settings...")),
era_combo_(disp, std::vector<std::string>()),
vision_combo_(disp, std::vector<std::string>()),
name_entry_(disp, 32),
minimap_restorer_(NULL),
minimap_rect_(null_rect),
generator_(NULL)
{
//build the list of scenarios to play
get_files_in_dir(get_user_data_dir() + "/editor/maps",&user_maps_,NULL,FILE_NAME_ONLY);
map_options_ = user_maps_;
const config::child_list& levels = cfg.get_children("multiplayer");
for(config::child_list::const_iterator j = levels.begin(); j != levels.end(); ++j){
map_options_.push_back((**j)["name"]);
}
//add the 'load game' option
map_options_.push_back(_("Load Game") + std::string("..."));
//create the scenarios menu
maps_menu_.set_items(map_options_);
maps_menu_.move_selection(0);
maps_menu_.set_numeric_keypress_selection(false);
turns_slider_.set_min(20);
turns_slider_.set_max(100);
turns_slider_.set_value(50);
turns_slider_.set_help_string(_("The maximum turns the game will go for"));
village_gold_slider_.set_min(1);
village_gold_slider_.set_max(5);
village_gold_slider_.set_value(1);
village_gold_slider_.set_help_string(_("The amount of income each village yields per turn"));
xp_modifier_slider_.set_min(25);
xp_modifier_slider_.set_max(200);
xp_modifier_slider_.set_value(100);
xp_modifier_slider_.set_increment(10);
xp_modifier_slider_.set_help_string(_("The amount of experience a unit needs to advance"));
fog_game_.set_check(false);
fog_game_.set_help_string(_("Enemy units cannot be seen unless they are in range of your units"));
shroud_game_.set_check(false);
shroud_game_.set_help_string(_("The map is unknown until your units explore it"));
observers_game_.set_check(true);
observers_game_.set_help_string(_("Allow users who are not playing to watch the game"));
// The possible vision settings
std::vector<std::string> vision_types;
vision_types.push_back(_("Share View"));
vision_types.push_back(_("Share Maps"));
vision_types.push_back(_("Share None"));
vision_combo_.set_items(vision_types);
vision_combo_.set_selected(0);
// The possible eras to play
const config::child_list& era_list = cfg.get_children("era");
std::vector<std::string> eras;
for(config::child_list::const_iterator er = era_list.begin(); er != era_list.end(); ++er) {
eras.push_back((**er)["name"]);
}
if(eras.empty()) {
gui::show_dialog(disp, NULL, "", _("No multiplayer sides."), gui::OK_ONLY);
std::cerr << "ERROR: no eras found\n";
throw config::error(_("No eras found"));
}
era_combo_.set_items(eras);
era_combo_.set_selected(0);
string_map i18n_symbols;
i18n_symbols["login"] = preferences::login();
name_entry_.set_text(vgettext("$login's game", i18n_symbols));
gamelist_updated();
}
create::parameters& create::get_parameters()
{
const config::child_list& era_list = game_config().get_children("era");
const int turns = turns_slider_.value() < turns_slider_.max_value() ?
turns_slider_.value() : -1;
// Updates the values in the "parameters_" member to match the values
// selected by the user with the widgets:
parameters_.name = name_entry_.text();
if (size_t(era_combo_.selected()) >= era_list.size()) {
throw config::error(_("Invalid era selected"));
}
parameters_.era = (*era_list[era_combo_.selected()])["id"];
parameters_.num_turns = turns;
parameters_.village_gold = village_gold_slider_.value();
parameters_.xp_modifier = xp_modifier_slider_.value();
parameters_.fog_game = fog_game_.checked();
parameters_.shroud_game = shroud_game_.checked();
parameters_.allow_observers = observers_game_.checked();
parameters_.share_view = vision_combo_.selected() == 0;
parameters_.share_maps = vision_combo_.selected() == 1;
return parameters_;
}
void create::process_event()
{
if(cancel_game_.pressed()) {
set_result(QUIT);
return;
}
if(launch_game_.pressed() || maps_menu_.double_clicked()) {
if(name_entry_.text() != "") {
set_result(CREATE);
return;
} else {
gui::show_dialog(disp(), NULL, "", _("You must enter a name."), gui::OK_ONLY);
}
}
// Turns per game
const int cur_turns = turns_slider_.value();
std::stringstream buf;
if(cur_turns < 100) {
buf << _("Turns") << ": " << cur_turns;
} else {
buf << _("Unlimited Turns");
}
turns_label_.set_text(buf.str());
//Villages can produce between 1 and 10 gold a turn
const int village_gold = village_gold_slider_.value();
buf.str("");
buf << _("Village Gold") << ": " << village_gold;
village_gold_label_.set_text(buf.str());
//experience modifier
const int xpmod = xp_modifier_slider_.value();
buf.str("");
buf << _("Experience Modifier") << ": " << xpmod << "%";
xp_modifier_label_.set_text(buf.str());
bool map_changed = map_selection_ != maps_menu_.selection();
map_selection_ = maps_menu_.selection();
if(map_changed) {
generator_.assign(NULL);
tooltips::clear_tooltips(minimap_rect_);
const size_t select = size_t(maps_menu_.selection());
if(select < user_maps_.size()) {
parameters_.saved_game = false;
const config* const generic_multiplayer = game_config().child("generic_multiplayer");
if(generic_multiplayer != NULL) {
parameters_.scenario_data = *generic_multiplayer;
parameters_.scenario_data["map_data"] = read_map(user_maps_[select]);
}
} else if(select != maps_menu_.nitems()-1) {
parameters_.saved_game = false;
const size_t index = select - user_maps_.size();
const config::child_list& levels = game_config().get_children("multiplayer");
if(index < levels.size()) {
parameters_.scenario_data = *levels[index];
std::string& map_data = parameters_.scenario_data["map_data"];
if(map_data == "" && parameters_.scenario_data["map"] != "") {
map_data = read_map(parameters_.scenario_data["map"]);
}
//if the map should be randomly generated
if(parameters_.scenario_data["map_generation"] != "") {
generator_.assign(create_map_generator(parameters_.scenario_data["map_generation"],parameters_.scenario_data.child("generator")));
}
if(parameters_.scenario_data["description"].empty() == false) {
tooltips::add_tooltip(minimap_rect_,parameters_.scenario_data["description"]);
}
}
} else {
parameters_.scenario_data.clear();
parameters_.saved_game = true;
if (minimap_restorer_ != NULL)
minimap_restorer_->restore();
}
}
if(generator_ != NULL && generator_->allow_user_config() && generator_settings_.pressed()) {
generator_->user_config(disp());
map_changed = true;
}
if(generator_ != NULL && (map_changed || regenerate_map_.pressed())) {
const cursor::setter cursor_setter(cursor::WAIT);
//generate the random map
parameters_.scenario_data = generator_->create_scenario(std::vector<std::string>());
map_changed = true;
//set the scenario to have placing of sides based on the terrain they prefer
parameters_.scenario_data["modify_placing"] = "true";
}
if(map_changed) {
generator_settings_.hide(generator_ == NULL);
regenerate_map_.hide(generator_ == NULL);
const std::string& map_data = parameters_.scenario_data["map_data"];
gamemap map(game_config(), map_data);
//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 = parameters_.scenario_data.get_children("side").size(); pos < map_positions; ++pos) {
config& side = parameters_.scenario_data.add_child("side");
side["enemy"] = "1";
char buf[50];
sprintf(buf,"%d",(pos+1));
side["side"] = buf;
side["team_name"] = buf;
side["canrecruit"] = "1";
side["controller"] = "human";
}
//if there are too many sides, remove some
while(int(parameters_.scenario_data.get_children("side").size()) > map_positions) {
parameters_.scenario_data.remove_child("side",
parameters_.scenario_data.get_children("side").size()-1);
}
const surface mini(image::getMinimap(minimap_rect_.w,minimap_rect_.h,map,0));
if(mini != NULL) {
SDL_Rect rect = minimap_rect_;
SDL_BlitSurface(mini, NULL, disp().video().getSurface(), &rect);
update_rect(rect);
}
const int nsides = parameters_.scenario_data.get_children("side").size();
std::stringstream players;
players << _("Players") << ": " << nsides;
num_players_label_.set_text(players.str());
}
}
void create::hide_children(bool hide)
{
ui::hide_children(hide);
maps_menu_.hide(hide);
turns_slider_.hide(hide);
turns_label_.hide(hide);
village_gold_slider_.hide(hide);
village_gold_label_.hide(hide);
xp_modifier_slider_.hide(hide);
xp_modifier_label_.hide(hide);
name_entry_label_.hide(hide);
num_players_label_.hide(hide);
era_label_.hide(hide);
map_label_.hide(hide);
fog_game_.hide(hide);
shroud_game_.hide(hide);
observers_game_.hide(hide);
cancel_game_.hide(hide);
launch_game_.hide(hide);
regenerate_map_.hide(hide);
generator_settings_.hide(hide);
era_combo_.hide(hide);
vision_combo_.hide(hide);
name_entry_.hide(hide);
if (hide) {
minimap_restorer_.assign(NULL);
} else {
minimap_restorer_.assign(new surface_restorer(&disp().video(), minimap_rect_));
const std::string& map_data = parameters_.scenario_data["map_data"];
gamemap map(game_config(), map_data);
const surface mini(image::getMinimap(minimap_rect_.w,minimap_rect_.h,map,0));
if(mini != NULL) {
SDL_Rect rect = minimap_rect_;
SDL_BlitSurface(mini, NULL, disp().video().getSurface(), &rect);
update_rect(rect);
}
}
}
void create::layout_children(const SDL_Rect& rect)
{
ui::layout_children(rect);
SDL_Rect ca = client_area();
const int border_size = 6;
int xpos = ca.x;
int ypos = ca.y;
// Dialog title
ypos += gui::draw_dialog_title(xpos, ypos, &disp(), _("Create Game")).h + border_size;
// Name Entry
name_entry_label_.set_location(xpos, ypos);
ypos += name_entry_label_.height() + border_size;
name_entry_.set_location(xpos, ypos);
name_entry_.set_width(ca.w);
ypos += name_entry_.height() + border_size;
// Save ypos here (column top)
int ypos_columntop = ypos;
// First column: minimap & era choice
const int minimap_width = 200;
SDL_Rect mmrect = { xpos, ypos, minimap_width, minimap_width };
minimap_rect_ = mmrect;
ypos += minimap_width + border_size;
num_players_label_.set_location(xpos, ypos);
ypos += num_players_label_.height() + border_size;
era_label_.set_location(xpos, ypos + (era_combo_.height() - era_label_.height()) / 2);
era_combo_.set_location(xpos + era_label_.width() + border_size, ypos);
// Second column: map menu
ypos = ypos_columntop + border_size;
xpos += minimap_width + border_size;
map_label_.set_location(xpos, ypos);
ypos += map_label_.height() + border_size;
maps_menu_.set_max_width(200);
maps_menu_.set_max_height(ca.x + ca.h - ypos);
maps_menu_.set_location(xpos, ypos);
// Menu dimensions are only updated when items are set. So do this now.
maps_menu_.set_items(map_options_);
maps_menu_.move_selection(map_selection_);
// Third column: big buch of options
ypos = ypos_columntop + border_size;
xpos += 200 + border_size;
turns_label_.set_location(xpos, ypos);
ypos += turns_label_.height() + border_size;
turns_slider_.set_width(ca.w - xpos);
turns_slider_.set_location(xpos, ypos);
ypos += turns_slider_.height() + border_size;
village_gold_label_.set_location(xpos, ypos);
ypos += village_gold_label_.height() + border_size;
village_gold_slider_.set_width(ca.w - xpos);
village_gold_slider_.set_location(xpos, ypos);
ypos += village_gold_slider_.height() + border_size;
xp_modifier_label_.set_location(xpos, ypos);
ypos += xp_modifier_label_.height() + border_size;
xp_modifier_slider_.set_width(ca.w - xpos);
xp_modifier_slider_.set_location(xpos, ypos);
ypos += xp_modifier_slider_.height() + border_size;
fog_game_.set_location(xpos, ypos);
ypos += fog_game_.height() + border_size;
shroud_game_.set_location(xpos, ypos);
ypos += shroud_game_.height() + border_size;
observers_game_.set_location(xpos, ypos);
ypos += observers_game_.height() + border_size;
vision_combo_.set_location(xpos, ypos);
ypos += vision_combo_.height() + border_size;
regenerate_map_.set_location(xpos, ypos);
ypos += regenerate_map_.height() + border_size;
generator_settings_.set_location(xpos, ypos);
// OK / Cancel buttons
gui::button* left_button = &launch_game_;
gui::button* right_button = &cancel_game_;
#ifdef OK_BUTTON_ON_RIGHT
std::swap(left_button,right_button);
#endif
// Buttons
right_button->set_location(ca.w - right_button->width(), ca.y + ca.h - right_button->height());
left_button->set_location(right_button->location().x - right_button->width(), ca.y + ca.h - right_button->height());
}
}

116
src/multiplayer_create.hpp Normal file
View file

@ -0,0 +1,116 @@
/* $Id$ */
/*
Copyright (C)
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.
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_HPP_INCLUDED
#define MULTIPLAYER_CREATE_HPP_INCLUDED
#include "multiplayer_ui.hpp"
#include "widgets/slider.hpp"
#include "widgets/label.hpp"
#include "widgets/combo.hpp"
#include "mapgen.hpp"
namespace mp {
class create : public mp::ui, public font::floating_label_context
{
public:
struct parameters
{
parameters() { reset(); };
void reset() {
name = "";
era = "";
num_turns = 0;
village_gold = 0;
xp_modifier = 0;
fog_game = shroud_game = allow_observers = share_view = share_maps = false;
scenario_data.clear();
}
// The items returned while configuring the game
std::string name;
std::string era;
int num_turns;
int village_gold;
int xp_modifier;
bool fog_game;
bool shroud_game;
bool allow_observers;
bool share_view;
bool share_maps;
bool saved_game;
// If the game is to be randomly generated, the map generator
// will create the scenario data in this variable:
config scenario_data;
};
create(display& dist, const config& game_config, chat& c, config& gamelist);
parameters& get_parameters();
protected:
virtual void layout_children(const SDL_Rect& rect);
virtual void process_event();
virtual void hide_children(bool hide=true);
private:
void update_minimap(void);
int map_selection_;
std::vector<std::string> user_maps_;
std::vector<std::string> map_options_;
gui::menu maps_menu_;
gui::slider turns_slider_;
gui::label turns_label_;
gui::slider village_gold_slider_;
gui::label village_gold_label_;
gui::slider xp_modifier_slider_;
gui::label xp_modifier_label_;
gui::label name_entry_label_;
gui::label num_players_label_;
gui::label era_label_;
gui::label map_label_;
gui::button fog_game_;
gui::button shroud_game_;
gui::button observers_game_;
gui::button cancel_game_;
gui::button launch_game_;
gui::button regenerate_map_;
gui::button generator_settings_;
gui::combo era_combo_;
gui::combo vision_combo_;
gui::textbox name_entry_;
util::scoped_ptr<surface_restorer> minimap_restorer_;
SDL_Rect minimap_rect_;
util::scoped_ptr<map_generator> generator_;
parameters parameters_;
};
}
#endif

292
src/multiplayer_ui.cpp Normal file
View file

@ -0,0 +1,292 @@
/* $Id$ */
/*
Copyright (C)
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.
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_ui.hpp"
#include "network.hpp"
#include "preferences.hpp"
#include "game_config.hpp"
#include "sound.hpp"
#define LOG_NW lg::info(lg::network)
#define ERR_NW lg::err(lg::network)
namespace mp {
void check_response(network::connection res, const config& data)
{
if(!res) {
throw network::error(_("Connection timed out"));
}
const config* err = data.child("error");
if(err != NULL) {
throw network::error((*err)["message"]);
}
}
chat::chat()
{
}
void chat::add_message(const std::string& user, const std::string& message)
{
message_history_.push_back(msg(user, message));
while (message_history_.size() > 1024) {
message_history_.pop_front();
if (last_update_ > 0)
last_update_--;
}
}
void chat::init_textbox(gui::textbox& textbox)
{
std::string s;
for(msg_hist::const_iterator itor = message_history_.begin();
itor != message_history_.end(); ++itor) {
s.append(format_message(*itor));
}
textbox.set_text(s);
last_update_ = message_history_.size();
}
void chat::update_textbox(gui::textbox& textbox)
{
std::string s;
for(msg_hist::const_iterator itor = message_history_.begin() + last_update_;
itor != message_history_.end(); ++itor) {
s.append(format_message(*itor));
}
textbox.append_text(s);
last_update_ = message_history_.size();
}
std::string chat::format_message(const msg& message)
{
return "<" + message.user + ">" + message.message + "\n";
}
ui::ui(display& disp, const config& cfg, chat& c, config& gamelist) :
gui::widget(disp),
game_config_(cfg),
chat_(c),
gamelist_(gamelist),
chat_textbox_(disp, 100, "", false),
entry_textbox_(disp, 100),
users_menu_(disp, std::vector<std::string>()),
result_(CONTINUE)
{
chat_.init_textbox(chat_textbox_);
}
void ui::process_network()
{
config data;
try {
const network::connection sock = network::receive_data(data);
if(sock) {
process_network_data(data, sock);
}
} catch(network::error& e) {
process_network_error(e);
}
if (accept_connections()) {
network::connection sock = network::accept_connection();
if(sock) {
LOG_NW << "Received connection\n";
process_network_connection(sock);
}
}
}
ui::result ui::get_result()
{
return result_;
}
ui::result ui::set_result(ui::result res)
{
result_ = res;
return res;
}
int ui::xscale(int x) const
{
return (x*disp().x())/1024;
}
int ui::yscale(int y) const
{
return (y*disp().y())/768;
}
SDL_Rect ui::client_area() const
{
SDL_Rect res = { xscale(11)+6, yscale(40)+6, xscale(833)-12, yscale(524)-12 };
return res;
}
const config& ui::game_config() const
{
return game_config_;
}
void ui::draw_contents()
{
hide_children();
surface background(image::get_image("misc/lobby.png",image::UNSCALED));
background = scale_surface(background, disp().x(), disp().y());
if(background == NULL)
return;
SDL_BlitSurface(background, NULL, disp().video().getSurface(), NULL);
update_whole_screen();
hide_children(false);
}
void ui::set_location(const SDL_Rect& rect)
{
hide_children();
widget::set_location(rect);
layout_children(rect);
hide_children(false);
}
void ui::process_event()
{
}
void ui::handle_event(const SDL_Event& event)
{
if(event.type == SDL_KEYDOWN) {
handle_key_event(event.key);
}
}
void ui::handle_key_event(const SDL_KeyboardEvent& event)
{
//On enter, adds the current chat message to the chat textbox.
if(event.keysym.sym == SDLK_RETURN && !entry_textbox_.text().empty()) {
// Sends the message to the network
config msg;
msg["message"] = entry_textbox_.text();
msg["sender"] = preferences::login();
config data;
data.add_child("message", msg);
network::send_data(data);
chat_.add_message(preferences::login(), entry_textbox_.text());
chat_.update_textbox(chat_textbox_);
entry_textbox_.clear();
}
}
void ui::process_network_data(const config& data, const network::connection sock)
{
if(data.child("error")) {
throw network::error((*data.child("error"))["message"]);
} else {
if(data.child("message")) {
sound::play_sound(game_config::sounds::receive_message);
const config& msg = *data.child("message");
chat_.add_message(msg["sender"], msg["message"]);
chat_.update_textbox(chat_textbox_);
}
if(data.child("gamelist")) {
gamelist_ = data;
gamelist_updated();
} else if(data.child("gamelist_diff")) {
gamelist_.apply_diff(*data.child("gamelist_diff"));
gamelist_updated();
}
}
}
void ui::process_network_error(network::error& error)
{
ERR_NW << "Caught networking error: " << error.message << "\n";
// Default behaviour is to re-throw the error. May be overridden.
throw error;
}
void ui::process_network_connection(const network::connection sock)
{
LOG_NW << "Caught network connection.\n";
}
void ui::hide_children(bool hide)
{
chat_textbox_.hide(hide);
entry_textbox_.hide(hide);
users_menu_.hide(hide);
}
void ui::layout_children(const SDL_Rect& rect)
{
users_menu_.set_width(xscale(156));
users_menu_.set_location(xscale(856),yscale(42));
chat_textbox_.set_location(xscale(11) + 4, xscale(573) + 4);
chat_textbox_.set_measurements(xscale(833) - 8, xscale(143) - 8);
entry_textbox_.set_location(xscale(11) + 4,yscale(732));
entry_textbox_.set_width(xscale(833) - 8);
}
void ui::gamelist_updated()
{
std::vector<std::string> user_strings;
config::child_list users = gamelist_.get_children("user");
config::child_iterator user;
for (user = users.begin(); user != users.end(); ++user) {
const std::string prefix = (**user)["available"] == "no" ? "#" : "";
user_strings.push_back(prefix + (**user)["name"]);
}
set_user_list(user_strings);
}
void ui::set_user_list(const std::vector<std::string>& list)
{
const int old_users = user_list_.size();
user_list_ = list;
const int new_users = user_list_.size();
if(new_users < old_users) {
sound::play_sound(game_config::sounds::user_leave);
} else if(new_users > old_users) {
sound::play_sound(game_config::sounds::user_arrive);
}
users_menu_.set_items(user_list_);
}
}

156
src/multiplayer_ui.hpp Normal file
View file

@ -0,0 +1,156 @@
/* $Id$ */
/*
Copyright (C)
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.
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_UI_HPP_INCLUDED
#define MULTIPLAYER_UI_HPP_INCLUDED
#include "multiplayer.hpp"
#include "widgets/textbox.hpp"
#include "widgets/button.hpp"
#include "widgets/menu.hpp"
#include "network.hpp"
#include "config.hpp"
#include <deque>
#include <string>
namespace mp {
void check_response(network::connection res, const config& data);
//this class memorizes a chat session.
class chat
{
public:
chat();
void add_message(const std::string& user, const std::string& message);
void init_textbox(gui::textbox& textbox);
void update_textbox(gui::textbox& textbox);
private:
struct msg {
msg(const std::string& user, const std::string& message) :
user(user), message(message) {};
std::string user;
std::string message;
};
typedef std::deque<msg> msg_hist;
std::string format_message(const msg& message);
msg_hist message_history_;
msg_hist::size_type last_update_;
};
//a base class for the different multiplayer base dialogs: game list, create
//game, wait game, game setup
class ui : public gui::widget
{
public:
enum result { CONTINUE, JOIN, OBSERVE, CREATE, PLAY, QUIT };
ui(display& d, const config& cfg, chat& c, config& gamelist);
// Asks the multiplayer_ui to pump some data from the network, and then
// to process it. The actual processing will be left to the child
// classes, through process_network_data and process_network_error
void process_network();
// Returns the result of the current widget. While the result is equal
// to continue, the widget should not be destroyed.
result get_result();
// Hides children, moves them (using layout_children), then shows them.
// The methodes hide_children and layout_children are supposed to be
// overridden by subclasses of this class which add new sub-widgets.
void set_location(const SDL_Rect& rect);
using widget::set_location;
protected:
int xscale(int x) const;
int yscale(int y) const;
SDL_Rect client_area() const;
// Returns the main game config, as defined by loading the preprocessed
// WML files. Children of this class may need this to obtain, for
// example, the list of available eras.
const config& game_config() const;
virtual void draw_contents();
virtual void process_event();
virtual void handle_event(const SDL_Event& event);
virtual void handle_key_event(const SDL_KeyboardEvent& event);
// Processes any pending network data. Called by the public
// process_network() method. Overridden by subclasses who add more
// behaviour for network.
virtual void process_network_data(const config& data, const network::connection sock);
// Processes any pending network error. Called by the public
// process_network() method. Overridden by subclasses
virtual void process_network_error(network::error& error);
// Return true if we must accept incoming connections, false if not.
// Defaults to not.
virtual bool accept_connections() { return false; };
// Processes a pending network connection.
virtual void process_network_connection(const network::connection sock);
// Hides or shows all gui::widget children of this widget. Should be
// overridden by subclasses which add their own children.
virtual void hide_children(bool hide=true);
// Lays the children out. This method is to be overridden by the
// subclasses of the mp_ui class; it will be called
virtual void layout_children(const SDL_Rect& rect);
// Sets the result of this dialog, to be checked by get_result()
result set_result(result res);
// Called each time the gamelist_ variable is updated. May be
// overridden by child classes to add custom gamelist behaviour.
virtual void gamelist_updated();
// Sets the user list
void set_user_list(const std::vector<std::string>&);
// Returns the current gamelist
config& gamelist() { return gamelist_; };
private:
// The main game configuration, as defined by loading the preprocessed
// WML files. Access using the game_config() method if necessary.
const config& game_config_;
chat& chat_;
config& gamelist_;
gui::textbox chat_textbox_;
gui::textbox entry_textbox_;
gui::menu users_menu_;
std::vector<std::string> user_list_;
result result_;
};
}
#endif