Removed GUI1 mp dialog code
The code removed in connect_engine was used by and relied on code in multiplayer_ui.hpp, which is now removed.
This commit is contained in:
parent
52105fdb4d
commit
d5fab53976
21 changed files with 1 additions and 6838 deletions
|
@ -868,15 +868,8 @@ set(wesnoth-main_SRC
|
|||
movetype.cpp
|
||||
mp_game_settings.cpp
|
||||
game_initialization/mp_game_utils.cpp
|
||||
game_initialization/mp_options.cpp
|
||||
mp_ui_alerts.cpp
|
||||
game_initialization/multiplayer.cpp
|
||||
game_initialization/multiplayer_configure.cpp
|
||||
game_initialization/multiplayer_connect.cpp
|
||||
game_initialization/multiplayer_create.cpp
|
||||
game_initialization/multiplayer_lobby.cpp
|
||||
game_initialization/multiplayer_ui.cpp
|
||||
game_initialization/multiplayer_wait.cpp
|
||||
network_asio.cpp
|
||||
pathfind/pathfind.cpp
|
||||
pathfind/teleport.cpp
|
||||
|
|
|
@ -323,13 +323,6 @@ wesnoth_sources = Split("""
|
|||
game_initialization/depcheck.cpp
|
||||
game_initialization/flg_manager.cpp
|
||||
game_initialization/mp_game_utils.cpp
|
||||
game_initialization/mp_options.cpp
|
||||
game_initialization/multiplayer_configure.cpp
|
||||
game_initialization/multiplayer_connect.cpp
|
||||
game_initialization/multiplayer_create.cpp
|
||||
game_initialization/multiplayer_lobby.cpp
|
||||
game_initialization/multiplayer_ui.cpp
|
||||
game_initialization/multiplayer_wait.cpp
|
||||
game_initialization/multiplayer.cpp
|
||||
game_initialization/playcampaign.cpp
|
||||
game_initialization/singleplayer.cpp
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "map/map.hpp"
|
||||
#include "game_initialization/multiplayer_ui.hpp"
|
||||
#include "game_initialization/mp_game_utils.hpp"
|
||||
#include "mt_rng.hpp"
|
||||
#include "game_initialization/playcampaign.hpp"
|
||||
|
@ -1417,29 +1416,6 @@ void side_engine::add_controller_option(ng::controller controller,
|
|||
controller_options_.push_back(std::make_pair(controller, name));
|
||||
}
|
||||
|
||||
std::vector<std::string> side_engine::get_colors() const
|
||||
{
|
||||
std::vector<std::string> res;
|
||||
for (int i = 0; i < num_colors(); ++i) {
|
||||
res.push_back(mp::get_color_string(get_color(i)));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string side_engine::get_color(int index) const
|
||||
{
|
||||
if(index == -1) {
|
||||
index = color();
|
||||
}
|
||||
if(!custom_color_.empty()) {
|
||||
if(index == 0) {
|
||||
return custom_color_;
|
||||
}
|
||||
index -= 1;
|
||||
}
|
||||
return std::to_string(index + 1);
|
||||
}
|
||||
|
||||
int side_engine::num_colors() const
|
||||
{
|
||||
return custom_color_.empty() ? gamemap::MAX_PLAYERS : gamemap::MAX_PLAYERS + 1;
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
#include "config.hpp"
|
||||
#include "flg_manager.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include "multiplayer_ui.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include <set>
|
||||
|
||||
namespace rand_rng { class mt_rng; }
|
||||
|
@ -222,8 +220,6 @@ public:
|
|||
{ return parent_.player_teams_; }
|
||||
flg_manager& flg() { return flg_; }
|
||||
|
||||
std::vector<std::string> get_colors() const;
|
||||
std::string get_color(int index = -1) const;
|
||||
int num_colors() const;
|
||||
|
||||
const std::string color_id() const { return color_id_; }
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "game_config_manager.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "game_initialization/mp_options.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "units/id.hpp"
|
||||
#include "wesnothd_connection_error.hpp"
|
||||
|
|
|
@ -1,598 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2012 - 2016 by Boldizsár Lipka <lipkab@zoho.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 "game_initialization/mp_options.hpp"
|
||||
#include "font/standard_colors.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "gui/auxiliary/find_widget.hpp"
|
||||
#include "gui/core/window_builder.hpp"
|
||||
#include "gui/dialogs/transient_message.hpp"
|
||||
#include "gui/widgets/button.hpp"
|
||||
#include "gui/widgets/slider.hpp"
|
||||
#include "gui/widgets/text_box.hpp"
|
||||
#include "gui/widgets/toggle_button.hpp"
|
||||
#include "widgets/slider.hpp"
|
||||
#include "widgets/textbox.hpp"
|
||||
#include "utils/functional.hpp"
|
||||
|
||||
static lg::log_domain log_mp_create_options("mp/create/options");
|
||||
#define DBG_MP LOG_STREAM(debug, log_mp_create_options)
|
||||
|
||||
namespace mp
|
||||
{
|
||||
|
||||
namespace options
|
||||
{
|
||||
|
||||
void manager::init_info(const config& cfg, const std::string& key)
|
||||
{
|
||||
for (const config& comp : cfg.child_range(key)) {
|
||||
config entry;
|
||||
entry["id"] = comp["id"];
|
||||
entry["name"] = comp["name"];
|
||||
|
||||
if (comp.has_child("options") && comp["allow_new_game"].to_bool(true)) {
|
||||
const config& options = comp.child("options");
|
||||
|
||||
for (const config::any_child& c : options.all_children_range()) {
|
||||
entry.add_child(c.key, c.cfg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We need to store components even if they don't have any options in
|
||||
// order to have set_xxx_by_index work properly
|
||||
options_info_.add_child(key, entry);
|
||||
}
|
||||
}
|
||||
|
||||
void manager::init_widgets()
|
||||
{
|
||||
for (option_display* od : widgets_ordered_) {
|
||||
delete od;
|
||||
}
|
||||
|
||||
widgets_.clear();
|
||||
widgets_ordered_.clear();
|
||||
|
||||
for (const config::any_child& comp : options_info_.all_children_range()) {
|
||||
if (comp.cfg.all_children_count() == 0 || !is_active(comp.cfg["id"])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
widgets_ordered_.push_back(new title_display(video_, comp.cfg["name"]));
|
||||
for (const config::any_child& c : comp.cfg.all_children_range()) {
|
||||
const std::string id = c.cfg["id"];
|
||||
if (c.key == "slider") {
|
||||
widgets_ordered_.push_back(new slider_display(video_, c.cfg));
|
||||
} else if (c.key == "entry") {
|
||||
widgets_ordered_.push_back(new entry_display(video_, c.cfg));
|
||||
} else if (c.key == "checkbox") {
|
||||
widgets_ordered_.push_back(new checkbox_display(video_, c.cfg));
|
||||
} else if (c.key == "combo") {
|
||||
widgets_ordered_.push_back(new combo_display(video_, c.cfg));
|
||||
}
|
||||
widgets_ordered_.back()->set_value(get_stored_value(id));
|
||||
widgets_[id] = widgets_ordered_.back();
|
||||
}
|
||||
widgets_ordered_.push_back(new reset_display(video_, comp.cfg["id"], *this));
|
||||
}
|
||||
}
|
||||
|
||||
void manager::restore_defaults(const std::string &component)
|
||||
{
|
||||
for (const config::any_child& i : get_component_cfg(component).all_children_range()) {
|
||||
if (!is_valid_option(i.key, i.cfg)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string id = i.cfg["id"].str();
|
||||
|
||||
widgets_[id]->set_value(get_default_value(id));
|
||||
}
|
||||
}
|
||||
|
||||
bool manager::has_options() const
|
||||
{
|
||||
return !widgets_.empty();
|
||||
}
|
||||
|
||||
manager::manager(const config &gamecfg, CVideo &video, gui::scrollpane *pane, const config &values)
|
||||
: options_info_()
|
||||
, values_(values)
|
||||
, video_(video)
|
||||
, pane_(pane)
|
||||
, era_()
|
||||
, scenario_()
|
||||
, is_campaign_()
|
||||
, modifications_()
|
||||
, widgets_()
|
||||
, widgets_ordered_()
|
||||
{
|
||||
DBG_MP << "Initializing the options manager" << std::endl;
|
||||
init_info(gamecfg, "modification");
|
||||
init_info(gamecfg, "era");
|
||||
init_info(gamecfg, "multiplayer");
|
||||
init_info(gamecfg, "campaign");
|
||||
|
||||
for (const config::any_child& i : options_info_.all_children_range())
|
||||
{
|
||||
for (const config::any_child& j : i.cfg.all_children_range())
|
||||
{
|
||||
if (is_valid_option(j.key, j.cfg)) {
|
||||
config& value = get_value_cfg(j.cfg["id"]);
|
||||
value["value"] = get_stored_value(j.cfg["id"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init_widgets();
|
||||
}
|
||||
|
||||
manager::~manager()
|
||||
{
|
||||
for (option_display* od : widgets_ordered_)
|
||||
{
|
||||
delete od;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void manager::set_values(const config& c)
|
||||
{
|
||||
values_ = c;
|
||||
}
|
||||
|
||||
void manager::set_era(const std::string& era)
|
||||
{
|
||||
era_ = era;
|
||||
}
|
||||
|
||||
void manager::set_scenario(const std::string& scenario)
|
||||
{
|
||||
is_campaign_ = false;
|
||||
scenario_ = scenario;
|
||||
}
|
||||
|
||||
void manager::set_campaign(const std::string& campaign)
|
||||
{
|
||||
is_campaign_ = true;
|
||||
scenario_ = campaign;
|
||||
}
|
||||
|
||||
void manager::set_modifications(const std::vector<std::string>& modifications)
|
||||
{
|
||||
modifications_ = modifications;
|
||||
}
|
||||
|
||||
void manager::layout_widgets(int startx, int starty, int w)
|
||||
{
|
||||
int ypos = starty;
|
||||
int border_size = 3;
|
||||
for (option_display* od : widgets_ordered_)
|
||||
{
|
||||
od->layout(startx, ypos, w, border_size, pane_);
|
||||
ypos += border_size;
|
||||
}
|
||||
}
|
||||
|
||||
void manager::process_event()
|
||||
{
|
||||
for (size_t i = 0; i<widgets_ordered_.size(); ++i)
|
||||
{
|
||||
widgets_ordered_[i]->process_event();
|
||||
}
|
||||
}
|
||||
|
||||
void manager::hide_children(bool hide)
|
||||
{
|
||||
for (std::map<std::string, option_display*>::iterator i = widgets_.begin();
|
||||
i != widgets_.end(); ++i)
|
||||
{
|
||||
i->second->hide_children(hide);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const config &manager::get_values()
|
||||
{
|
||||
update_values();
|
||||
return values_;
|
||||
}
|
||||
|
||||
config& manager::get_value_cfg(const std::string& id)
|
||||
{
|
||||
{
|
||||
config& value_cfg = values_.find_child("option", "id", id);
|
||||
if(value_cfg) {
|
||||
return value_cfg;
|
||||
}
|
||||
}
|
||||
|
||||
config::any_child info = get_option_parent(id);
|
||||
config* parent_cfg;
|
||||
if (!values_.find_child(info.key, "id", info.cfg["id"])) {
|
||||
parent_cfg = &values_.add_child(info.key);
|
||||
(*parent_cfg)["id"] = info.cfg["id"];
|
||||
} else {
|
||||
parent_cfg = &values_.find_child(info.key, "id", info.cfg["id"]);
|
||||
}
|
||||
|
||||
config& value_cfg = parent_cfg->add_child("option");
|
||||
value_cfg["id"] = id;
|
||||
|
||||
return value_cfg;
|
||||
}
|
||||
|
||||
const config& manager::get_value_cfg_or_empty(const std::string& id) const
|
||||
{
|
||||
static const config empty;
|
||||
const config& cfg = values_.find_child("option", "id", id);
|
||||
return cfg ? cfg : empty;
|
||||
}
|
||||
|
||||
config::any_child manager::get_option_parent(const std::string& id) const
|
||||
{
|
||||
static config empty;
|
||||
static const std::string empty_key = "";
|
||||
static const config::any_child not_found(&empty_key, &empty);
|
||||
|
||||
for (const config::any_child& i : options_info_.all_children_range()) {
|
||||
for (const config::any_child& j : i.cfg.all_children_range()) {
|
||||
if (j.cfg["id"] == id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return not_found;
|
||||
}
|
||||
|
||||
const config& manager::get_option_info_cfg(const std::string& id) const
|
||||
{
|
||||
static const config empty;
|
||||
|
||||
for (const config::any_child& i : options_info_.all_children_range()) {
|
||||
for (const config::any_child& j : i.cfg.all_children_range()) {
|
||||
if (j.cfg["id"] == id) {
|
||||
return j.cfg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return empty;
|
||||
}
|
||||
|
||||
const config& manager::get_component_cfg(const std::string &id) const
|
||||
{
|
||||
static const config empty;
|
||||
const config &m = options_info_.find_child("modification", "id", id);
|
||||
if (m) {
|
||||
return m;
|
||||
}
|
||||
const config &s = options_info_.find_child("scenario", "id", id);
|
||||
if (s) {
|
||||
return s;
|
||||
}
|
||||
const config &e = options_info_.find_child("era", "id", id);
|
||||
if (e) {
|
||||
return e;
|
||||
}
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
||||
config::attribute_value manager::get_stored_value(const std::string& id) const
|
||||
{
|
||||
const config& valcfg = get_value_cfg_or_empty(id);
|
||||
|
||||
if (!valcfg["value"].empty()) {
|
||||
// There's a saved value for this option
|
||||
return valcfg["value"];
|
||||
}
|
||||
|
||||
// Fall back to the option's default
|
||||
return get_default_value(id);
|
||||
}
|
||||
|
||||
config::attribute_value manager::get_default_value(const std::string& id) const
|
||||
{
|
||||
const config& optinfo = get_option_info_cfg(id);
|
||||
|
||||
return optinfo["default"];
|
||||
}
|
||||
|
||||
void manager::extract_values(const std::string& key, const std::string& id)
|
||||
{
|
||||
for (const config::any_child& c : options_info_.find_child(key, "id", id).all_children_range())
|
||||
{
|
||||
if (!is_valid_option(c.key, c.cfg)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
config& out = get_value_cfg(c.cfg["id"].str());
|
||||
out["value"] = widgets_[c.cfg["id"]]->get_value();
|
||||
}
|
||||
}
|
||||
|
||||
void manager::update_values()
|
||||
{
|
||||
extract_values("era", era_);
|
||||
if (is_campaign_) {
|
||||
extract_values("campaign", scenario_);
|
||||
}
|
||||
else {
|
||||
extract_values("multiplayer", scenario_);
|
||||
}
|
||||
for (const std::string& str : modifications_) {
|
||||
extract_values("modification", str);
|
||||
}
|
||||
}
|
||||
|
||||
bool manager::is_valid_option(const std::string& key, const config& option)
|
||||
{
|
||||
return (key == "slider" || key == "entry" || key == "checkbox" || key == "combo") &&
|
||||
(!option["id"].empty());
|
||||
}
|
||||
|
||||
bool manager::is_active(const std::string &id) const
|
||||
{
|
||||
return (era_ == id) || (scenario_ == id) ||
|
||||
(std::find(modifications_.begin(), modifications_.end(), id) != modifications_.end());
|
||||
}
|
||||
|
||||
entry_display::entry_display(CVideo &video, const config &cfg) :
|
||||
entry_(new gui::textbox(video, 150, cfg["default"])),
|
||||
label_(new gui::label(video, cfg["name"]))
|
||||
{
|
||||
entry_->set_help_string(cfg["description"]);
|
||||
}
|
||||
|
||||
entry_display::~entry_display()
|
||||
{
|
||||
delete entry_;
|
||||
delete label_;
|
||||
}
|
||||
|
||||
void entry_display::layout(int &xpos, int &ypos, int /*w*/, int border_size, gui::scrollpane *pane)
|
||||
{
|
||||
pane->add_widget(label_, xpos, ypos);
|
||||
pane->add_widget(entry_, xpos + label_->width() + border_size, ypos);
|
||||
ypos += std::max(label_->height(), entry_->height()) + border_size;
|
||||
}
|
||||
|
||||
void entry_display::set_value(const config::attribute_value &val)
|
||||
{
|
||||
entry_->set_text(val);
|
||||
}
|
||||
|
||||
config::attribute_value entry_display::get_value() const
|
||||
{
|
||||
config::attribute_value res;
|
||||
res = entry_->text();
|
||||
return res;
|
||||
}
|
||||
|
||||
void entry_display::hide_children(bool hide)
|
||||
{
|
||||
label_->hide(hide);
|
||||
entry_->hide(hide);
|
||||
}
|
||||
|
||||
slider_display::slider_display(CVideo &video, const config &cfg) :
|
||||
slider_(new gui::slider(video)),
|
||||
label_(new gui::label(video, cfg["name"], font::SIZE_SMALL)),
|
||||
last_value_(cfg["default"].to_int()),
|
||||
label_text_(cfg["name"])
|
||||
{
|
||||
slider_->set_min(cfg["min"].to_int());
|
||||
slider_->set_max(cfg["max"].to_int());
|
||||
slider_->set_increment(cfg["step"].to_int());
|
||||
slider_->set_value(cfg["default"].to_int());
|
||||
|
||||
slider_->set_help_string(cfg["description"]);
|
||||
|
||||
update_label();
|
||||
}
|
||||
|
||||
slider_display::~slider_display()
|
||||
{
|
||||
delete slider_;
|
||||
delete label_;
|
||||
}
|
||||
|
||||
void slider_display::layout(int &xpos, int &ypos, int w, int border_size, gui::scrollpane *pane)
|
||||
{
|
||||
pane->add_widget(label_, xpos, ypos);
|
||||
ypos += label_->height() + border_size;
|
||||
pane->add_widget(slider_, xpos, ypos);
|
||||
slider_->set_width(w - border_size);
|
||||
ypos += slider_->height() + border_size;
|
||||
}
|
||||
|
||||
void slider_display::set_value(const config::attribute_value &val)
|
||||
{
|
||||
slider_->set_value(val.to_int());
|
||||
}
|
||||
|
||||
config::attribute_value slider_display::get_value() const
|
||||
{
|
||||
config::attribute_value res;
|
||||
res = slider_->value();
|
||||
return res;
|
||||
}
|
||||
|
||||
void slider_display::process_event()
|
||||
{
|
||||
if (slider_->value() != last_value_) {
|
||||
last_value_ = slider_->value();
|
||||
update_label();
|
||||
}
|
||||
}
|
||||
|
||||
void slider_display::hide_children(bool hide)
|
||||
{
|
||||
label_->hide(hide);
|
||||
slider_->hide(hide);
|
||||
}
|
||||
|
||||
void slider_display::update_label()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << label_text_ << ' ' << last_value_;
|
||||
label_->set_text(ss.str());
|
||||
}
|
||||
|
||||
checkbox_display::checkbox_display(CVideo &video, const config &cfg) :
|
||||
checkbox_(new gui::button(video, cfg["name"], gui::button::TYPE_CHECK))
|
||||
{
|
||||
checkbox_->set_check(cfg["default"].to_bool());
|
||||
checkbox_->set_help_string(cfg["description"]);
|
||||
}
|
||||
|
||||
checkbox_display::~checkbox_display()
|
||||
{
|
||||
delete checkbox_;
|
||||
}
|
||||
|
||||
void checkbox_display::layout(int &xpos, int &ypos, int /*w*/, int border_size, gui::scrollpane *pane)
|
||||
{
|
||||
pane->add_widget(checkbox_, xpos, ypos);
|
||||
ypos += checkbox_->height() + border_size;
|
||||
}
|
||||
|
||||
void checkbox_display::set_value(const config::attribute_value &val)
|
||||
{
|
||||
checkbox_->set_check(val.to_bool());
|
||||
}
|
||||
|
||||
config::attribute_value checkbox_display::get_value() const
|
||||
{
|
||||
config::attribute_value res;
|
||||
res = checkbox_->checked();
|
||||
return res;
|
||||
}
|
||||
|
||||
void checkbox_display::hide_children(bool hide)
|
||||
{
|
||||
checkbox_->hide(hide);
|
||||
}
|
||||
|
||||
title_display::title_display(CVideo &video, const std::string &label) :
|
||||
title_(new gui::label(video, "`~" + label, font::SIZE_PLUS, font::LOBBY_COLOR))
|
||||
{}
|
||||
|
||||
title_display::~title_display()
|
||||
{
|
||||
delete title_;
|
||||
}
|
||||
|
||||
void title_display::layout(int &xpos, int &ypos, int /*w*/, int border_size, gui::scrollpane *pane)
|
||||
{
|
||||
ypos += 4*border_size;
|
||||
pane->add_widget(title_, xpos, ypos);
|
||||
ypos += title_->height() + 2*border_size;
|
||||
}
|
||||
|
||||
void title_display::hide_children(bool hide)
|
||||
{
|
||||
title_->hide(hide);
|
||||
}
|
||||
|
||||
combo_display::combo_display(CVideo &video, const config &cfg) :
|
||||
label_(new gui::label(video, cfg["name"])),
|
||||
combo_(new gui::combo(video, std::vector<std::string>())),
|
||||
values_()
|
||||
{
|
||||
std::vector<std::string> items;
|
||||
for (const config& item : cfg.child_range("item")) {
|
||||
items.push_back(item["name"]);
|
||||
values_.push_back(item["value"]);
|
||||
}
|
||||
|
||||
combo_->set_items(items);
|
||||
combo_->set_help_string(cfg["description"]);
|
||||
set_value(cfg["default"]);
|
||||
}
|
||||
|
||||
combo_display::~combo_display()
|
||||
{
|
||||
delete label_;
|
||||
delete combo_;
|
||||
}
|
||||
|
||||
void combo_display::layout(int &xpos, int &ypos, int /*w*/, int border_size, gui::scrollpane *pane)
|
||||
{
|
||||
pane->add_widget(label_, xpos, ypos);
|
||||
pane->add_widget(combo_, xpos + label_->width() + border_size, ypos);
|
||||
ypos += std::max(label_->height(), combo_->height()) + border_size;
|
||||
}
|
||||
|
||||
void combo_display::set_value(const config::attribute_value &val)
|
||||
{
|
||||
const std::string value = val;
|
||||
for (size_t i = 0; i<values_.size(); i++) {
|
||||
if (value == values_[i]) {
|
||||
combo_->set_selected(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value combo_display::get_value() const
|
||||
{
|
||||
config::attribute_value res;
|
||||
res = values_[combo_->selected()];
|
||||
return res;
|
||||
}
|
||||
|
||||
void combo_display::hide_children(bool hide)
|
||||
{
|
||||
label_->hide(hide);
|
||||
combo_->hide(hide);
|
||||
}
|
||||
|
||||
reset_display::reset_display(CVideo &video, const std::string &comp, manager &m)
|
||||
: manager_(m)
|
||||
, component_(comp)
|
||||
, button_(new gui::button(video, _("Defaults")))
|
||||
{}
|
||||
|
||||
reset_display::~reset_display()
|
||||
{
|
||||
delete button_;
|
||||
}
|
||||
|
||||
void reset_display::layout(int &/*xpos*/, int &ypos, int w, int border_size, gui::scrollpane *pane)
|
||||
{
|
||||
pane->add_widget(button_, w-border_size-button_->width(), ypos);
|
||||
ypos += button_->height() + border_size;
|
||||
}
|
||||
|
||||
void reset_display::hide_children(bool hide)
|
||||
{
|
||||
button_->hide(hide);
|
||||
}
|
||||
|
||||
void reset_display::process_event()
|
||||
{
|
||||
if (button_->pressed()) {
|
||||
manager_.restore_defaults(component_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace options
|
||||
|
||||
} // namespace mp
|
||||
|
|
@ -1,358 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2012 - 2016 by Boldizsár Lipka <lipkab@zoho.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 MP_OPTIONS_HPP_INCLUDED
|
||||
#define MP_OPTIONS_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include "config.hpp"
|
||||
#include "gui/widgets/widget.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "widgets/scrollpane.hpp"
|
||||
#include "widgets/label.hpp"
|
||||
#include "widgets/button.hpp"
|
||||
#include "widgets/textbox.hpp"
|
||||
#include "widgets/slider.hpp"
|
||||
#include "widgets/combo.hpp"
|
||||
|
||||
namespace mp
|
||||
{
|
||||
|
||||
namespace options
|
||||
{
|
||||
|
||||
class option_display
|
||||
{
|
||||
public:
|
||||
virtual ~option_display() {}
|
||||
virtual void layout(int& xpos, int& ypos, int w, int border_size, gui::scrollpane* pane) = 0;
|
||||
virtual void set_value(const config::attribute_value& val) = 0;
|
||||
virtual config::attribute_value get_value() const = 0;
|
||||
virtual void process_event() {}
|
||||
virtual void hide_children(bool hide) = 0;
|
||||
};
|
||||
|
||||
class entry_display : public option_display
|
||||
{
|
||||
public:
|
||||
entry_display(CVideo& video, const config& cfg);
|
||||
~entry_display();
|
||||
|
||||
void layout(int &xpos, int &ypos, int w, int border_size, gui::scrollpane *pane);
|
||||
void set_value(const config::attribute_value &val);
|
||||
config::attribute_value get_value() const;
|
||||
virtual void hide_children(bool hide);
|
||||
|
||||
private:
|
||||
gui::textbox* entry_;
|
||||
gui::label* label_;
|
||||
};
|
||||
|
||||
class slider_display : public option_display
|
||||
{
|
||||
public:
|
||||
slider_display(CVideo& video, const config& cfg);
|
||||
~slider_display();
|
||||
|
||||
void layout(int &xpos, int &ypos, int w, int border_size, gui::scrollpane *pane);
|
||||
void set_value(const config::attribute_value &val);
|
||||
config::attribute_value get_value() const;
|
||||
void process_event();
|
||||
virtual void hide_children(bool hide);
|
||||
|
||||
private:
|
||||
void update_label();
|
||||
|
||||
gui::slider* slider_;
|
||||
gui::label* label_;
|
||||
int last_value_;
|
||||
const std::string label_text_;
|
||||
};
|
||||
|
||||
class checkbox_display : public option_display
|
||||
{
|
||||
public:
|
||||
checkbox_display(CVideo& video, const config& cfg);
|
||||
~checkbox_display();
|
||||
|
||||
void layout(int &xpos, int &ypos, int w, int border_size, gui::scrollpane *pane);
|
||||
void set_value(const config::attribute_value &val);
|
||||
config::attribute_value get_value() const;
|
||||
virtual void hide_children(bool hide);
|
||||
private:
|
||||
gui::button* checkbox_;
|
||||
};
|
||||
|
||||
class combo_display : public option_display
|
||||
{
|
||||
public:
|
||||
combo_display(CVideo& video, const config& cfg);
|
||||
~combo_display();
|
||||
|
||||
void layout(int &xpos, int &ypos, int w, int border_size, gui::scrollpane *pane);
|
||||
void set_value(const config::attribute_value &val);
|
||||
config::attribute_value get_value() const;
|
||||
void hide_children(bool hide);
|
||||
|
||||
private:
|
||||
gui::label* label_;
|
||||
gui::combo* combo_;
|
||||
|
||||
std::vector<std::string> values_;
|
||||
};
|
||||
|
||||
class title_display : public option_display
|
||||
{
|
||||
public:
|
||||
title_display(CVideo& video, const std::string& label);
|
||||
~title_display();
|
||||
|
||||
void layout(int &xpos, int &ypos, int w, int border_size, gui::scrollpane *pane);
|
||||
void set_value(const config::attribute_value &/*val*/) {}
|
||||
config::attribute_value get_value() const { return config::attribute_value(); }
|
||||
virtual void hide_children(bool hide);
|
||||
|
||||
private:
|
||||
gui::label* title_;
|
||||
};
|
||||
|
||||
class manager;
|
||||
|
||||
class reset_display : public option_display
|
||||
{
|
||||
public:
|
||||
reset_display(CVideo& video, const std::string& comp, manager &m);
|
||||
~reset_display();
|
||||
|
||||
void layout(int &xpos, int &ypos, int w, int border_size, gui::scrollpane *pane);
|
||||
void set_value(const config::attribute_value &/*val*/) {}
|
||||
config::attribute_value get_value() const { return config::attribute_value(); }
|
||||
void hide_children(bool hide);
|
||||
void process_event();
|
||||
|
||||
private:
|
||||
manager &manager_;
|
||||
std::string component_;
|
||||
gui::button* button_;
|
||||
};
|
||||
|
||||
class manager
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param gamecfg The config object holding all eras, scenarios
|
||||
* and modifications.
|
||||
*
|
||||
* @param display The screen to display the dialog on.
|
||||
*
|
||||
* @param initial_value The initial values for each option.
|
||||
*/
|
||||
manager(const config& gamecfg, CVideo& video, gui::scrollpane* pane, const config& initial_value);
|
||||
|
||||
~manager();
|
||||
|
||||
/**
|
||||
* Set the current values the options. This overrides ALL previously set
|
||||
* values, even if a not all options are provided a new value for.
|
||||
*
|
||||
* @param values The new values for each option.
|
||||
*/
|
||||
void set_values(const config& values);
|
||||
|
||||
/**
|
||||
* Sets the selected era. Whenever show_dialog is called, only
|
||||
* options for the selected era will be displayed.
|
||||
*
|
||||
* @param id The era's id.
|
||||
*/
|
||||
void set_era(const std::string& id);
|
||||
|
||||
/**
|
||||
* Sets the selected scenario. Whenever show_dialog is called, only
|
||||
* options for the selected scenario will be displayed.
|
||||
*
|
||||
* @param id The scenario's id.
|
||||
*/
|
||||
void set_scenario(const std::string& id);
|
||||
|
||||
/**
|
||||
* Sets the selected campaign. Whenever show_dialog is called, only
|
||||
* options for the campaign scenario will be displayed.
|
||||
*
|
||||
* @param id The campaign's id.
|
||||
*/
|
||||
void set_campaign(const std::string& id);
|
||||
|
||||
/**
|
||||
* Sets the activated modifications. Whenever show_dialog is called, only
|
||||
* options for the activated modifications will be displayed.
|
||||
*
|
||||
* @param ids The ids of the modifications
|
||||
*/
|
||||
void set_modifications(const std::vector<std::string>& ids);
|
||||
|
||||
void layout_widgets(int startx, int starty, int w);
|
||||
void process_event();
|
||||
void hide_children(bool hide=true);
|
||||
|
||||
/**
|
||||
* Returns the the values for each option.
|
||||
*
|
||||
* @return A config containing the values.
|
||||
*/
|
||||
const config& get_values();
|
||||
|
||||
void init_widgets();
|
||||
|
||||
void restore_defaults(const std::string &component);
|
||||
|
||||
bool has_options() const;
|
||||
private:
|
||||
|
||||
/** Stores needed info about each element and their configuration options */
|
||||
config options_info_;
|
||||
|
||||
/** Stores the selected values for each option */
|
||||
config values_;
|
||||
|
||||
/** The screen to display the dialog on */
|
||||
CVideo& video_;
|
||||
|
||||
/** The scrollarea to put the widgets on */
|
||||
gui::scrollpane* pane_;
|
||||
|
||||
/** The id of the selected era */
|
||||
std::string era_;
|
||||
|
||||
/** The id of the selected [multiplayer] or [campaign]*/
|
||||
std::string scenario_;
|
||||
bool is_campaign_;
|
||||
/** The ids of the selected modifications */
|
||||
std::vector<std::string> modifications_;
|
||||
|
||||
std::map<std::string, option_display*> widgets_;
|
||||
std::vector<option_display*> widgets_ordered_;
|
||||
|
||||
/**
|
||||
* Adds the necessary information about the specified component
|
||||
* to options_info_.
|
||||
*
|
||||
* @param cfg The component's data.
|
||||
* @param key The component's type.
|
||||
*/
|
||||
void init_info(const config& cfg, const std::string& key);
|
||||
|
||||
/**
|
||||
* Returns the node which holds the selected value of an option. If that
|
||||
* node is not yet created, the function creates it.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return A reference to the config which the value
|
||||
* for this option should be written into.
|
||||
*/
|
||||
config& get_value_cfg(const std::string& id);
|
||||
|
||||
/**
|
||||
* Returns the node which holds the selected value of an option. If that
|
||||
* node is not yet created, the function returns an empty config.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return A reference to the config which the value
|
||||
* for this option should be written into or
|
||||
* an empty config if that doesn't exist.
|
||||
*/
|
||||
const config& get_value_cfg_or_empty(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Returns the information about an option.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return The config object which contains the
|
||||
* settings of the option, or an empty config
|
||||
* if the option was not found.
|
||||
*/
|
||||
const config& get_option_info_cfg(const std::string& id) const;
|
||||
|
||||
const config& get_component_cfg(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Finds the parent node of an options.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return A config::any_child object containing the
|
||||
* key and the data of the parent node, or ""
|
||||
* for the key and an empty config if the
|
||||
* option was not found.
|
||||
*/
|
||||
config::any_child get_option_parent(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Retrieves the saved value for a certain option, or the default, if
|
||||
* there's no such.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return The value saved in values_ for this option
|
||||
* or its specified default value if a saved
|
||||
* value can't be found.
|
||||
*/
|
||||
config::attribute_value get_stored_value(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Retrieves the default value for a certain option.
|
||||
*
|
||||
* @param id The id of the option.
|
||||
*
|
||||
* @return The default value for this option.
|
||||
*/
|
||||
config::attribute_value get_default_value(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* Writes all the values for the options of a certain component from a
|
||||
* specified window into values_.
|
||||
*
|
||||
* @param key The component's type.
|
||||
* @param id The component's id.
|
||||
*/
|
||||
void extract_values(const std::string& key, const std::string& id);
|
||||
|
||||
void update_values();
|
||||
|
||||
/**
|
||||
* Decides whether a config is a sane option node or not.
|
||||
* A valid option node:
|
||||
* - Must have an id field.
|
||||
* - Its key must be "slider", "entry" or "checkbox"
|
||||
*
|
||||
* @param key The option's key.
|
||||
* @param option The option's data.
|
||||
*
|
||||
* @return True if the option is valid, false if not.
|
||||
*/
|
||||
static bool is_valid_option(const std::string& key, const config& option);
|
||||
|
||||
bool is_active(const std::string& id) const;
|
||||
};
|
||||
|
||||
} // namespace options
|
||||
|
||||
} // namespace mp
|
||||
#endif
|
|
@ -38,13 +38,8 @@
|
|||
#include "log.hpp"
|
||||
#include "generators/map_create.hpp"
|
||||
#include "game_initialization/mp_game_utils.hpp"
|
||||
#include "game_initialization/multiplayer_configure.hpp"
|
||||
#include "game_initialization/configure_engine.hpp"
|
||||
#include "game_initialization/multiplayer_connect.hpp"
|
||||
#include "game_initialization/multiplayer_create.hpp"
|
||||
#include "multiplayer_error_codes.hpp"
|
||||
#include "game_initialization/multiplayer_wait.hpp"
|
||||
#include "game_initialization/multiplayer_lobby.hpp"
|
||||
#include "game_initialization/playcampaign.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "scripting/plugins/context.hpp"
|
||||
|
|
|
@ -1,714 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2013 - 2016 Boldizsár Lipka <lipkab@zoho.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 "global.hpp"
|
||||
|
||||
#include "gettext.hpp"
|
||||
#include "game_preferences.hpp"
|
||||
#include "construct_dialog.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "map/map.hpp"
|
||||
#include "map/exception.hpp"
|
||||
#include "generators/map_create.hpp"
|
||||
#include "gui/dialogs/message.hpp"
|
||||
#include "gui/dialogs/multiplayer/mp_create_game_set_password.hpp"
|
||||
#include "gui/dialogs/transient_message.hpp"
|
||||
#include "minimap.hpp"
|
||||
#include "mp_game_settings.hpp"
|
||||
#include "game_initialization/multiplayer_configure.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "log.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include "scripting/plugins/context.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
#include "wml_separators.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "font/standard_colors.hpp"
|
||||
|
||||
#include "utils/functional.hpp"
|
||||
|
||||
static lg::log_domain log_config("config");
|
||||
#define ERR_CF LOG_STREAM(err, log_config)
|
||||
|
||||
static lg::log_domain log_mp_configure("mp/configure");
|
||||
#define DBG_MP LOG_STREAM(debug, log_mp_configure)
|
||||
|
||||
namespace mp {
|
||||
|
||||
configure::nolock_settings::nolock_settings(CVideo& video)
|
||||
: turns_slider_(video)
|
||||
, turns_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR)
|
||||
, village_gold_slider_(video)
|
||||
, village_gold_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR)
|
||||
, village_support_slider_(video)
|
||||
, village_support_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR)
|
||||
, xp_modifier_slider_(video)
|
||||
, xp_modifier_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR)
|
||||
, generic_label_(video, "`~ " + _("Generic"), font::SIZE_PLUS, font::LOBBY_COLOR)
|
||||
, use_map_settings_(video, _("Use map settings"), gui::button::TYPE_CHECK)
|
||||
, random_start_time_(video, _("Random start time"), gui::button::TYPE_CHECK)
|
||||
, fog_game_(video, _("Fog of war"), gui::button::TYPE_CHECK)
|
||||
, shroud_game_(video, _("Shroud"), gui::button::TYPE_CHECK)
|
||||
{
|
||||
|
||||
}
|
||||
configure::configure(CVideo& video, wesnothd_connection* connection, const config &cfg, chat& c, config& gamelist, saved_game& game, bool local_players_only) :
|
||||
ui(video, connection, _("Configure Game"), cfg, c, gamelist),
|
||||
|
||||
local_players_only_(local_players_only),
|
||||
tooltip_manager_(video),
|
||||
mp_countdown_init_time_(270),
|
||||
mp_countdown_reservoir_time_(330),
|
||||
|
||||
countdown_game_(video, _("Time limit"), gui::button::TYPE_CHECK),
|
||||
countdown_init_time_slider_(video),
|
||||
countdown_init_time_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
countdown_reservoir_time_slider_(video),
|
||||
countdown_reservoir_time_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
countdown_turn_bonus_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
countdown_turn_bonus_slider_(video),
|
||||
countdown_action_bonus_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
countdown_action_bonus_slider_(video),
|
||||
name_entry_label_(video, _("Name of game:"), font::SIZE_PLUS, font::LOBBY_COLOR),
|
||||
observers_game_(video, _("Observers"), gui::button::TYPE_CHECK),
|
||||
registered_users_only_(video, _("Registered users only"), gui::button::TYPE_CHECK),
|
||||
oos_debug_(video, _("Debug OOS"), gui::button::TYPE_CHECK),
|
||||
shuffle_sides_(video, _("Shuffle sides"), gui::button::TYPE_CHECK),
|
||||
random_faction_mode_label_(video, _("Random factions:"), font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
random_faction_mode_(video, std::vector<std::string>()),
|
||||
cancel_game_(video, _("Back")),
|
||||
launch_game_(video, _("OK")),
|
||||
password_button_(video, _("Set Password...")),
|
||||
name_entry_(video, 32),
|
||||
entry_points_label_(video, _("Select an entry point:"), font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
entry_points_combo_(video, std::vector<std::string>()),
|
||||
options_pane_left_(video),
|
||||
options_pane_right_(video),
|
||||
entry_points_(),
|
||||
show_entry_points_(false),
|
||||
force_use_map_settings_check_(false),
|
||||
state_(game),
|
||||
parameters_(state_.mp_settings()),
|
||||
engine_(state_),
|
||||
options_manager_(cfg, video, &options_pane_right_, engine_.options_default()),
|
||||
nolock_settings_(engine_.force_lock_settings() ? 0 : new nolock_settings(video))
|
||||
{
|
||||
// Build the list of scenarios to play
|
||||
|
||||
DBG_MP << "constructing multiplayer configure dialog" << std::endl;
|
||||
|
||||
countdown_game_.set_check(engine_.mp_countdown_default());
|
||||
countdown_game_.set_help_string(_("Enables user time limit"));
|
||||
|
||||
countdown_init_time_slider_.set_min(30);
|
||||
countdown_init_time_slider_.set_max(1500);
|
||||
countdown_init_time_slider_.set_increment(30);
|
||||
countdown_init_time_slider_.set_value(engine_.mp_countdown_init_time_default());
|
||||
countdown_init_time_slider_.set_help_string(_("Longest time allowed for first turn (seconds)"));
|
||||
|
||||
countdown_reservoir_time_slider_.set_min(30);
|
||||
countdown_reservoir_time_slider_.set_max(1500);
|
||||
countdown_reservoir_time_slider_.set_increment(30);
|
||||
countdown_reservoir_time_slider_.set_value(engine_.mp_countdown_reservoir_time_default());
|
||||
countdown_reservoir_time_slider_.set_help_string(_("Longest time possible for any turn (seconds)"));
|
||||
|
||||
countdown_turn_bonus_slider_.set_min(10);
|
||||
countdown_turn_bonus_slider_.set_max(300);
|
||||
countdown_turn_bonus_slider_.set_increment(5);
|
||||
countdown_turn_bonus_slider_.set_value(engine_.mp_countdown_turn_bonus_default());
|
||||
countdown_turn_bonus_slider_.set_help_string(_("Time for general tasks each turn (seconds)"));
|
||||
|
||||
countdown_action_bonus_slider_.set_min(0);
|
||||
countdown_action_bonus_slider_.set_max(30);
|
||||
countdown_action_bonus_slider_.set_increment(1);
|
||||
countdown_action_bonus_slider_.set_value(engine_.mp_countdown_action_bonus_default());
|
||||
countdown_action_bonus_slider_.set_help_string(_("Time for each attack, recruit, and capture"));
|
||||
|
||||
observers_game_.set_check(engine_.allow_observers_default());
|
||||
observers_game_.set_help_string(_("Allow users who are not playing to watch the game"));
|
||||
observers_game_.enable(state_.classification().campaign_type != game_classification::CAMPAIGN_TYPE::SCENARIO);
|
||||
|
||||
registered_users_only_.set_check(engine_.registered_users_only_default());
|
||||
registered_users_only_.set_help_string(_("Allow only registered users to join the game"));
|
||||
registered_users_only_.enable(state_.classification().campaign_type != game_classification::CAMPAIGN_TYPE::SCENARIO);
|
||||
|
||||
oos_debug_.set_check(false);
|
||||
oos_debug_.set_help_string(_("More checks for OOS errors but also more network traffic"));
|
||||
oos_debug_.enable(true);
|
||||
|
||||
shuffle_sides_.set_check(engine_.shuffle_sides_default());
|
||||
shuffle_sides_.set_help_string(_("Assign sides to players at random"));
|
||||
|
||||
random_faction_mode_label_.set_help_string(_("Allow for mirror matchups when random factions are chosen"));
|
||||
|
||||
std::vector<std::string> translated_modes;
|
||||
for(size_t i = 0; i < mp_game_settings::RANDOM_FACTION_MODE::count; ++i) {
|
||||
std::string mode_str = mp_game_settings::RANDOM_FACTION_MODE::from_int(i).to_string();
|
||||
translated_modes.push_back(translation::gettext(mode_str.c_str()));
|
||||
}
|
||||
random_faction_mode_.set_items(translated_modes);
|
||||
random_faction_mode_.set_selected(engine_.random_faction_mode().cast<int>());
|
||||
random_faction_mode_.set_help_string(_("Independent: Random factions assigned independently\nNo Mirror: No two players will get the same faction\nNo Ally Mirror: No two allied players will get the same faction"));
|
||||
|
||||
if(nolock_settings_) {
|
||||
nolock_settings_->use_map_settings_.enable(!engine_.force_lock_settings());
|
||||
nolock_settings_->use_map_settings_.set_check(engine_.use_map_settings());
|
||||
nolock_settings_->use_map_settings_.set_help_string(_("Use scenario specific settings"));
|
||||
|
||||
nolock_settings_->turns_slider_.set_min(settings::turns_min);
|
||||
nolock_settings_->turns_slider_.set_max(settings::turns_max);
|
||||
nolock_settings_->turns_slider_.set_increment(settings::turns_step);
|
||||
nolock_settings_->turns_slider_.set_value(engine_.num_turns_default());
|
||||
nolock_settings_->turns_slider_.set_help_string(_("The maximum number of turns the game can last"));
|
||||
nolock_settings_->turns_slider_.enable(!engine_.use_map_settings());
|
||||
|
||||
nolock_settings_->village_gold_slider_.set_min(1);
|
||||
nolock_settings_->village_gold_slider_.set_max(5);
|
||||
nolock_settings_->village_gold_slider_.set_value(engine_.village_gold_default());
|
||||
nolock_settings_->village_gold_slider_.set_help_string(_("The amount of income each village yields per turn"));
|
||||
nolock_settings_->village_gold_slider_.enable(!engine_.use_map_settings());
|
||||
|
||||
nolock_settings_->village_support_slider_.set_min(0);
|
||||
nolock_settings_->village_support_slider_.set_max(4);
|
||||
nolock_settings_->village_support_slider_.set_value(engine_.village_support_default());
|
||||
nolock_settings_->village_support_slider_.set_help_string(_("The number of unit levels each village can support"));
|
||||
nolock_settings_->village_support_slider_.enable(!engine_.use_map_settings());
|
||||
|
||||
nolock_settings_->xp_modifier_slider_.set_min(30);
|
||||
nolock_settings_->xp_modifier_slider_.set_max(200);
|
||||
nolock_settings_->xp_modifier_slider_.set_value(engine_.xp_modifier_default());
|
||||
nolock_settings_->xp_modifier_slider_.set_increment(10);
|
||||
nolock_settings_->xp_modifier_slider_.set_help_string(_("The amount of experience a unit needs to advance"));
|
||||
nolock_settings_->xp_modifier_slider_.enable(!engine_.use_map_settings());
|
||||
|
||||
nolock_settings_->random_start_time_.set_check(engine_.random_start_time_default());
|
||||
nolock_settings_->random_start_time_.set_help_string(_("Randomize time of day in begin"));
|
||||
nolock_settings_->random_start_time_.enable(!engine_.use_map_settings());
|
||||
|
||||
nolock_settings_->fog_game_.set_check(engine_.fog_game_default());
|
||||
nolock_settings_->fog_game_.set_help_string(_("Enemy units cannot be seen unless they are in range of your units"));
|
||||
nolock_settings_->fog_game_.enable(!engine_.use_map_settings());
|
||||
|
||||
nolock_settings_->shroud_game_.set_check(engine_.shroud_game_default());
|
||||
nolock_settings_->shroud_game_.set_help_string(_("The map is unknown until your units explore it"));
|
||||
nolock_settings_->shroud_game_.enable(!engine_.use_map_settings());
|
||||
}
|
||||
#if 0
|
||||
// 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"));
|
||||
#endif
|
||||
// The starting points for campaign.
|
||||
|
||||
if (engine_.entry_point_titles().size() > 1) {
|
||||
entry_points_combo_.set_items(engine_.entry_point_titles());
|
||||
entry_points_combo_.set_selected(0);
|
||||
|
||||
show_entry_points_ = true;
|
||||
}
|
||||
|
||||
options_manager_.set_era(parameters_.mp_era);
|
||||
if(state_.classification().campaign.empty()) {
|
||||
options_manager_.set_scenario(state_.get_scenario_id());
|
||||
}
|
||||
else {
|
||||
options_manager_.set_campaign(state_.classification().campaign);
|
||||
}
|
||||
options_manager_.set_modifications(parameters_.active_mods);
|
||||
options_manager_.init_widgets();
|
||||
|
||||
name_entry_.set_text(engine_.game_name_default());
|
||||
|
||||
gamelist_updated();
|
||||
|
||||
plugins_context_.reset(new plugins_context("Multiplayer Configure"));
|
||||
|
||||
//These structure initializers create a lobby::process_data_event
|
||||
plugins_context_->set_callback("launch", std::bind(&configure::plugin_event_helper, this, process_event_data (true, false)));
|
||||
plugins_context_->set_callback("quit", std::bind(&configure::plugin_event_helper, this, process_event_data (false, true)));
|
||||
plugins_context_->set_callback("set_name", [this](const config& cfg) { name_entry_.set_text(cfg["name"], font::NORMAL_COLOR); }, true);
|
||||
|
||||
if(!options_manager_.has_options() && engine_.force_lock_settings() && state_.classification().campaign_type != game_classification::CAMPAIGN_TYPE::MULTIPLAYER) {
|
||||
set_result(CREATE);
|
||||
}
|
||||
}
|
||||
|
||||
configure::~configure()
|
||||
{
|
||||
try {
|
||||
// Only save the settings if the dialog was 'accepted'
|
||||
if(get_result() != CREATE) {
|
||||
DBG_MP << "destructing multiplayer configure dialog - aborted game creation" << std::endl;
|
||||
return;
|
||||
}
|
||||
DBG_MP << "destructing multiplayer configure dialog - a game will be configured" << std::endl;
|
||||
|
||||
// Save values for next game
|
||||
DBG_MP << "storing parameter values in preferences" << std::endl;
|
||||
preferences::set_shuffle_sides(engine_.shuffle_sides());
|
||||
preferences::set_random_faction_mode(engine_.random_faction_mode().to_string());
|
||||
preferences::set_use_map_settings(engine_.use_map_settings());
|
||||
preferences::set_countdown(engine_.mp_countdown());
|
||||
preferences::set_countdown_init_time(engine_.mp_countdown_init_time());
|
||||
preferences::set_countdown_turn_bonus(engine_.mp_countdown_turn_bonus());
|
||||
preferences::set_countdown_reservoir_time(engine_.mp_countdown_reservoir_time());
|
||||
preferences::set_countdown_action_bonus(engine_.mp_countdown_action_bonus());
|
||||
preferences::set_options(engine_.options());
|
||||
// don't set observers preference if disabled (for singleplayer)
|
||||
if (observers_game_.enabled())
|
||||
preferences::set_allow_observers(engine_.allow_observers());
|
||||
// don't set registered_users_only preference if disabled (for singleplayer)
|
||||
if (registered_users_only_.enabled())
|
||||
preferences::set_registered_users_only(engine_.registered_users_only());
|
||||
|
||||
// When using map settings, the following variables are determined by the map,
|
||||
// so don't store them as the new preferences.
|
||||
if(!engine_.use_map_settings()) {
|
||||
preferences::set_fog(engine_.fog_game());
|
||||
preferences::set_shroud(engine_.shroud_game());
|
||||
preferences::set_turns(engine_.num_turns());
|
||||
preferences::set_random_start_time(engine_.random_start_time());
|
||||
preferences::set_village_gold(engine_.village_gold());
|
||||
preferences::set_village_support(engine_.village_support());
|
||||
preferences::set_xp_modifier(engine_.xp_modifier());
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
void configure::get_parameters()
|
||||
{
|
||||
DBG_MP << "getting parameter values from widgets" << std::endl;
|
||||
|
||||
const int mp_countdown_turn_bonus_val = countdown_turn_bonus_slider_.value() <= countdown_turn_bonus_slider_.max_value() ?
|
||||
countdown_turn_bonus_slider_.value() : -1;
|
||||
const int mp_countdown_action_bonus_val = countdown_action_bonus_slider_.value() <= countdown_action_bonus_slider_.max_value() ?
|
||||
countdown_action_bonus_slider_.value() : -1;
|
||||
const int mp_countdown_reservoir_time_val = countdown_reservoir_time_slider_.value() <= countdown_reservoir_time_slider_.max_value() ?
|
||||
countdown_reservoir_time_slider_.value() : -1;
|
||||
int mp_countdown_init_time_val = countdown_init_time_slider_.value() <= countdown_init_time_slider_.max_value() ?
|
||||
countdown_init_time_slider_.value() : -1;
|
||||
if(mp_countdown_reservoir_time_val > 0 && mp_countdown_init_time_val > mp_countdown_reservoir_time_val)
|
||||
mp_countdown_init_time_val = mp_countdown_reservoir_time_val;
|
||||
|
||||
// Updates the values in the configure_engine to match
|
||||
// the values selected by the user with the widgets:
|
||||
engine_.set_game_name(name_entry_.text());
|
||||
|
||||
// CHECK
|
||||
engine_.set_mp_countdown_init_time(mp_countdown_init_time_val);
|
||||
engine_.set_mp_countdown_turn_bonus(mp_countdown_turn_bonus_val);
|
||||
engine_.set_mp_countdown_reservoir_time(mp_countdown_reservoir_time_val);
|
||||
engine_.set_mp_countdown_action_bonus(mp_countdown_action_bonus_val);
|
||||
engine_.set_mp_countdown(countdown_game_.checked());
|
||||
if(nolock_settings_) {
|
||||
const int num_turns_val = nolock_settings_->turns_slider_.value() <
|
||||
nolock_settings_->turns_slider_.max_value() ? nolock_settings_->turns_slider_.value() : -1;
|
||||
engine_.set_num_turns(num_turns_val);
|
||||
engine_.set_village_gold(nolock_settings_->village_gold_slider_.value());
|
||||
engine_.set_village_support(nolock_settings_->village_support_slider_.value());
|
||||
engine_.set_xp_modifier(nolock_settings_->xp_modifier_slider_.value());
|
||||
engine_.set_use_map_settings(nolock_settings_->use_map_settings_.checked());
|
||||
engine_.set_random_start_time(nolock_settings_->random_start_time_.checked());
|
||||
engine_.set_fog_game(nolock_settings_->fog_game_.checked());
|
||||
engine_.set_shroud_game(nolock_settings_->shroud_game_.checked());
|
||||
engine_.write_parameters();
|
||||
}
|
||||
engine_.set_allow_observers(observers_game_.checked());
|
||||
engine_.set_registered_users_only(registered_users_only_.checked());
|
||||
engine_.set_oos_debug(oos_debug_.checked());
|
||||
engine_.set_shuffle_sides(shuffle_sides_.checked());
|
||||
engine_.set_random_faction_mode(mp_game_settings::RANDOM_FACTION_MODE::from_int(random_faction_mode_.selected()));
|
||||
|
||||
engine_.set_options(options_manager_.get_values());
|
||||
|
||||
}
|
||||
|
||||
bool configure::plugin_event_helper(const process_event_data & data)
|
||||
{
|
||||
process_event_impl(data);
|
||||
return get_result() == mp::ui::CONTINUE;
|
||||
}
|
||||
|
||||
void configure::process_event()
|
||||
{
|
||||
int mousex, mousey;
|
||||
SDL_GetMouseState(&mousex,&mousey);
|
||||
tooltips::process(mousex, mousey);
|
||||
|
||||
process_event_data data;
|
||||
data.launch = launch_game_.pressed();
|
||||
data.quit = cancel_game_.pressed();
|
||||
|
||||
process_event_impl(data);
|
||||
}
|
||||
|
||||
void configure::process_event_impl(const process_event_data & data)
|
||||
{
|
||||
if(data.quit) {
|
||||
set_result(QUIT);
|
||||
return;
|
||||
}
|
||||
|
||||
if(data.launch) {
|
||||
// check if the map is valid
|
||||
if (name_entry_.text() == "") {
|
||||
gui2::show_transient_message(video(), "", _("You must enter a name."));
|
||||
} else {
|
||||
set_result(CREATE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(password_button_.pressed()) {
|
||||
gui2::dialogs::mp_create_game_set_password::execute(
|
||||
parameters_.password
|
||||
, video());
|
||||
}
|
||||
|
||||
if (entry_points_combo_.changed()) {
|
||||
engine_.set_scenario(entry_points_combo_.selected());
|
||||
force_use_map_settings_check_ = true;
|
||||
}
|
||||
std::stringstream buf;
|
||||
if(nolock_settings_) {
|
||||
// Turns per game
|
||||
const int cur_turns = nolock_settings_->turns_slider_.value();
|
||||
|
||||
if(cur_turns < 100) {
|
||||
buf << _("Turns: ") << cur_turns;
|
||||
} else {
|
||||
buf << _("Unlimited turns");
|
||||
}
|
||||
nolock_settings_->turns_label_.set_text(buf.str());
|
||||
|
||||
|
||||
// Villages can produce between 1 and 5 gold a turn
|
||||
const int village_gold = nolock_settings_->village_gold_slider_.value();
|
||||
buf.str("");
|
||||
buf << _("Village gold: ") << village_gold;
|
||||
nolock_settings_->village_gold_label_.set_text(buf.str());
|
||||
|
||||
// Unit levels supported per village
|
||||
const int village_support = nolock_settings_->village_support_slider_.value();
|
||||
buf.str("");
|
||||
buf << _("Village support: ") << village_support;
|
||||
nolock_settings_->village_support_label_.set_text(buf.str());
|
||||
|
||||
// Experience modifier
|
||||
const int xpmod = nolock_settings_->xp_modifier_slider_.value();
|
||||
buf.str("");
|
||||
buf << _("Experience modifier: ") << xpmod << "%";
|
||||
|
||||
nolock_settings_->xp_modifier_label_.set_text(buf.str());
|
||||
|
||||
|
||||
if(nolock_settings_->use_map_settings_.pressed() || force_use_map_settings_check_) {
|
||||
force_use_map_settings_check_ = false;
|
||||
|
||||
engine_.set_use_map_settings(nolock_settings_->use_map_settings_.checked());
|
||||
|
||||
// If the map settings are wanted use them,
|
||||
// if not properly defined fall back to the default settings
|
||||
nolock_settings_->turns_slider_.set_value(engine_.num_turns_default());
|
||||
nolock_settings_->xp_modifier_slider_.set_value(engine_.xp_modifier_default());
|
||||
nolock_settings_->random_start_time_.set_check(engine_.random_start_time_default());
|
||||
nolock_settings_->village_gold_slider_.set_value(engine_.village_gold_default());
|
||||
nolock_settings_->village_support_slider_.set_value(engine_.village_support_default());
|
||||
nolock_settings_->fog_game_.set_check(engine_.fog_game_default());
|
||||
nolock_settings_->shroud_game_.set_check(engine_.shroud_game_default());
|
||||
|
||||
// Set the widget states
|
||||
nolock_settings_->turns_slider_.enable(!engine_.use_map_settings());
|
||||
nolock_settings_->village_gold_slider_.enable(!engine_.use_map_settings());
|
||||
nolock_settings_->village_support_slider_.enable(!engine_.use_map_settings());
|
||||
nolock_settings_->xp_modifier_slider_.enable(!engine_.use_map_settings());
|
||||
nolock_settings_->random_start_time_.enable(!engine_.use_map_settings());
|
||||
nolock_settings_->fog_game_.enable(!engine_.use_map_settings());
|
||||
nolock_settings_->shroud_game_.enable(!engine_.use_map_settings());
|
||||
}
|
||||
}
|
||||
countdown_init_time_label_.enable(countdown_game_.checked());
|
||||
countdown_init_time_slider_.enable(countdown_game_.checked());
|
||||
countdown_turn_bonus_label_.enable(countdown_game_.checked());
|
||||
countdown_turn_bonus_slider_.enable(countdown_game_.checked());
|
||||
|
||||
countdown_reservoir_time_label_.enable(countdown_game_.checked());
|
||||
countdown_reservoir_time_slider_.enable(countdown_game_.checked());
|
||||
countdown_action_bonus_label_.enable(countdown_game_.checked());
|
||||
countdown_action_bonus_slider_.enable(countdown_game_.checked());
|
||||
|
||||
if(mp_countdown_init_time_ != countdown_init_time_slider_.value()
|
||||
&& countdown_init_time_slider_.value() > countdown_reservoir_time_slider_.value())
|
||||
{
|
||||
countdown_reservoir_time_slider_.set_value(countdown_init_time_slider_.value());
|
||||
}
|
||||
if(mp_countdown_reservoir_time_ != countdown_reservoir_time_slider_.value()
|
||||
&& countdown_reservoir_time_slider_.value() < countdown_init_time_slider_.value())
|
||||
{
|
||||
countdown_init_time_slider_.set_value(countdown_reservoir_time_slider_.value());
|
||||
}
|
||||
mp_countdown_init_time_ = countdown_init_time_slider_.value();
|
||||
mp_countdown_reservoir_time_ = countdown_reservoir_time_slider_.value();
|
||||
|
||||
buf.str("");
|
||||
buf << _("Init. limit: ") << mp_countdown_init_time_; // << _(" sec.");
|
||||
countdown_init_time_label_.set_text(buf.str());
|
||||
|
||||
const int mp_countdown_turn_bonus_val = countdown_turn_bonus_slider_.value();
|
||||
buf.str("");
|
||||
buf << _("Turn bonus: ") << mp_countdown_turn_bonus_val; // << _(" sec.");
|
||||
countdown_turn_bonus_label_.set_text(buf.str());
|
||||
|
||||
buf.str("");
|
||||
buf << _("Reservoir: ") << mp_countdown_reservoir_time_; // << _(" sec.");
|
||||
countdown_reservoir_time_label_.set_text(buf.str());
|
||||
|
||||
const int mp_countdown_action_bonus_val = countdown_action_bonus_slider_.value();
|
||||
buf.str("");
|
||||
buf << _("Action bonus: ") << mp_countdown_action_bonus_val; // << _(" sec.");
|
||||
countdown_action_bonus_label_.set_text(buf.str());
|
||||
|
||||
options_manager_.process_event();
|
||||
}
|
||||
|
||||
void configure::hide_children(bool hide)
|
||||
{
|
||||
DBG_MP << (hide ? "hiding" : "showing" ) << " children widgets" << std::endl;
|
||||
|
||||
ui::hide_children(hide);
|
||||
if (nolock_settings_)
|
||||
{
|
||||
nolock_settings_->turns_slider_.hide(hide);
|
||||
nolock_settings_->turns_label_.hide(hide);
|
||||
nolock_settings_->village_gold_slider_.hide(hide);
|
||||
nolock_settings_->village_gold_label_.hide(hide);
|
||||
nolock_settings_->village_support_slider_.hide(hide);
|
||||
nolock_settings_->village_support_label_.hide(hide);
|
||||
nolock_settings_->xp_modifier_slider_.hide(hide);
|
||||
nolock_settings_->xp_modifier_label_.hide(hide);
|
||||
nolock_settings_->generic_label_.hide(hide);
|
||||
nolock_settings_->use_map_settings_.hide(hide);
|
||||
nolock_settings_->random_start_time_.hide(hide);
|
||||
nolock_settings_->fog_game_.hide(hide);
|
||||
nolock_settings_->shroud_game_.hide(hide);
|
||||
}
|
||||
|
||||
countdown_init_time_slider_.hide(hide);
|
||||
countdown_init_time_label_.hide(hide);
|
||||
countdown_turn_bonus_slider_.hide(hide);
|
||||
countdown_turn_bonus_label_.hide(hide);
|
||||
countdown_reservoir_time_slider_.hide(hide);
|
||||
countdown_reservoir_time_label_.hide(hide);
|
||||
countdown_action_bonus_slider_.hide(hide);
|
||||
countdown_action_bonus_label_.hide(hide);
|
||||
countdown_game_.hide(hide);
|
||||
|
||||
name_entry_label_.hide(hide);
|
||||
|
||||
observers_game_.hide(hide);
|
||||
registered_users_only_.hide(hide);
|
||||
oos_debug_.hide(hide);
|
||||
shuffle_sides_.hide(hide);
|
||||
random_faction_mode_label_.hide(hide);
|
||||
random_faction_mode_.hide(hide);
|
||||
cancel_game_.hide(hide);
|
||||
launch_game_.hide(hide);
|
||||
|
||||
password_button_.hide(hide);
|
||||
name_entry_.hide(hide);
|
||||
|
||||
entry_points_label_.hide(hide);
|
||||
entry_points_combo_.hide(hide);
|
||||
|
||||
options_pane_left_.hide(hide);
|
||||
options_pane_right_.hide(hide);
|
||||
|
||||
options_manager_.hide_children(hide);
|
||||
}
|
||||
|
||||
void configure::layout_children(const SDL_Rect& rect)
|
||||
{
|
||||
DBG_MP << "laying out the children" << std::endl;
|
||||
|
||||
ui::layout_children(rect);
|
||||
|
||||
const int border_size = 6;
|
||||
const int column_border_size = 10;
|
||||
|
||||
SDL_Rect ca = client_area();
|
||||
int xpos = ca.x;
|
||||
int ypos = ca.y;
|
||||
const int column_width = (ca.w - ca.x) / 2 - column_border_size;
|
||||
|
||||
// Dialog title
|
||||
ypos += title().height() + border_size;
|
||||
|
||||
// Name Entry
|
||||
name_entry_label_.set_location(xpos, ypos);
|
||||
name_entry_.set_location(xpos + name_entry_label_.width() + border_size, ypos);
|
||||
name_entry_.set_width(ca.w - name_entry_label_.width() - border_size);
|
||||
ypos += std::max<int>(name_entry_.height(), name_entry_label_.height()) + border_size;
|
||||
|
||||
// Save ypos here (column top)
|
||||
int ypos_columntop = ypos;
|
||||
|
||||
const int right_pane_height =
|
||||
ca.h - (ypos_columntop - ca.y + launch_game_.height() + border_size);
|
||||
|
||||
// First column: non-gameplay settings
|
||||
options_pane_left_.set_location(xpos, ypos);
|
||||
options_pane_left_.set_width(column_width);
|
||||
options_pane_left_.set_height(right_pane_height - entry_points_label_.height());
|
||||
|
||||
int slider_width = options_pane_left_.width() - 40;
|
||||
|
||||
int xpos_left = 0;
|
||||
int ypos_left = 0;
|
||||
|
||||
ypos_left += 2 * border_size;
|
||||
options_pane_left_.add_widget(&shuffle_sides_, xpos_left, ypos_left);
|
||||
options_pane_left_.add_widget(&observers_game_,
|
||||
xpos_left + options_pane_left_.width() / 3 + border_size, ypos_left);
|
||||
options_pane_left_.add_widget(®istered_users_only_,
|
||||
xpos_left + options_pane_left_.width() * 2/ 3 + border_size, ypos_left);
|
||||
ypos_left += shuffle_sides_.height() + border_size;
|
||||
|
||||
options_pane_left_.add_widget(&random_faction_mode_label_, xpos_left, ypos_left);
|
||||
xpos_left += random_faction_mode_label_.width() + border_size;
|
||||
|
||||
options_pane_left_.add_widget(&random_faction_mode_, xpos_left, ypos_left);
|
||||
xpos_left += random_faction_mode_.width() + border_size;
|
||||
|
||||
if(!local_players_only_) {
|
||||
options_pane_left_.add_widget(&password_button_,
|
||||
std::max(xpos_left + 2* border_size, (options_pane_left_.width() / 2) + border_size), ypos_left);
|
||||
} else {
|
||||
password_button_.hide(true);
|
||||
}
|
||||
xpos_left = 0;
|
||||
ypos_left += random_faction_mode_.height() + border_size;
|
||||
|
||||
options_pane_left_.add_widget(&countdown_game_, xpos_left, ypos_left);
|
||||
ypos_left += countdown_game_.height() + border_size;
|
||||
|
||||
options_pane_left_.add_widget(&countdown_init_time_label_, xpos_left, ypos_left );
|
||||
ypos_left += countdown_init_time_label_.height() + border_size;
|
||||
countdown_init_time_slider_.set_width(slider_width);
|
||||
options_pane_left_.add_widget(&countdown_init_time_slider_, xpos_left, ypos_left);
|
||||
ypos_left += countdown_init_time_slider_.height() + border_size;
|
||||
|
||||
options_pane_left_.add_widget(&countdown_turn_bonus_label_, xpos_left, ypos_left);
|
||||
ypos_left += countdown_turn_bonus_label_.height() + border_size;
|
||||
countdown_turn_bonus_slider_.set_width(slider_width);
|
||||
options_pane_left_.add_widget(&countdown_turn_bonus_slider_, xpos_left, ypos_left);
|
||||
ypos_left += countdown_turn_bonus_slider_.height() + border_size;
|
||||
|
||||
options_pane_left_.add_widget(&countdown_reservoir_time_label_, xpos_left, ypos_left);
|
||||
ypos_left += countdown_reservoir_time_label_.height() + border_size;
|
||||
countdown_reservoir_time_slider_.set_width(slider_width);
|
||||
options_pane_left_.add_widget(&countdown_reservoir_time_slider_, xpos_left, ypos_left);
|
||||
ypos_left += countdown_reservoir_time_slider_.height() + border_size;
|
||||
options_pane_left_.add_widget(&countdown_action_bonus_label_, xpos_left, ypos_left);
|
||||
ypos_left += countdown_action_bonus_label_.height() + border_size;
|
||||
countdown_action_bonus_slider_.set_width(slider_width);
|
||||
options_pane_left_.add_widget(&countdown_action_bonus_slider_, xpos_left, ypos_left);
|
||||
ypos_left += countdown_action_bonus_slider_.height() + border_size;
|
||||
|
||||
options_pane_left_.add_widget(&oos_debug_, xpos_left, ypos_left );
|
||||
ypos_left += oos_debug_.height() + border_size;
|
||||
|
||||
if (show_entry_points_) {
|
||||
int x = ca.x;
|
||||
int y = ca.y + ca.h - entry_points_combo_.height();
|
||||
entry_points_combo_.set_location(x, y);
|
||||
y -= entry_points_label_.height() + border_size;
|
||||
entry_points_label_.set_location(x, y);
|
||||
}
|
||||
|
||||
// Second column: gameplay settings
|
||||
xpos += column_width + column_border_size;
|
||||
ypos = ypos_columntop;
|
||||
|
||||
options_pane_right_.set_location(xpos, ypos);
|
||||
options_pane_right_.set_width(ca.w - (xpos - ca.x));
|
||||
options_pane_right_.set_height(right_pane_height);
|
||||
|
||||
slider_width = options_pane_right_.width() - 40;
|
||||
|
||||
int xpos_right = 0;
|
||||
int ypos_right = 0;
|
||||
if(nolock_settings_)
|
||||
{
|
||||
options_pane_right_.add_widget(&nolock_settings_->generic_label_, xpos_right, ypos_right);
|
||||
ypos_right += nolock_settings_->generic_label_.height() + border_size;
|
||||
|
||||
options_pane_right_.add_widget(&nolock_settings_->use_map_settings_, xpos_right, ypos_right);
|
||||
options_pane_right_.add_widget(&nolock_settings_->fog_game_,
|
||||
xpos_right + (options_pane_right_.width() - xpos_right)/2 + 5, ypos_right);
|
||||
ypos_right += nolock_settings_->use_map_settings_.height() + border_size;
|
||||
|
||||
options_pane_right_.add_widget(&nolock_settings_->random_start_time_, xpos_right, ypos_right);
|
||||
options_pane_right_.add_widget(&nolock_settings_->shroud_game_,
|
||||
xpos_right + (options_pane_right_.width() - xpos_right)/2 + 5, ypos_right);
|
||||
ypos_right += nolock_settings_->random_start_time_.height() + border_size;
|
||||
|
||||
options_pane_right_.add_widget(&nolock_settings_->turns_label_, xpos_right, ypos_right);
|
||||
ypos_right += nolock_settings_->turns_label_.height() + border_size;
|
||||
nolock_settings_->turns_slider_.set_width(slider_width);
|
||||
options_pane_right_.add_widget(&nolock_settings_->turns_slider_, xpos_right, ypos_right);
|
||||
ypos_right += nolock_settings_->turns_slider_.height() + border_size;
|
||||
|
||||
options_pane_right_.add_widget(&nolock_settings_->xp_modifier_label_, xpos_right, ypos_right);
|
||||
ypos_right += nolock_settings_->xp_modifier_label_.height() + border_size;
|
||||
nolock_settings_->xp_modifier_slider_.set_width(slider_width);
|
||||
options_pane_right_.add_widget(&nolock_settings_->xp_modifier_slider_, xpos_right, ypos_right);
|
||||
ypos_right += nolock_settings_->xp_modifier_slider_.height() + border_size;
|
||||
|
||||
options_pane_right_.add_widget(&nolock_settings_->village_support_label_, xpos_right, ypos_right);
|
||||
ypos_right += nolock_settings_->village_support_label_.height() + border_size;
|
||||
nolock_settings_->village_support_slider_.set_width(slider_width);
|
||||
options_pane_right_.add_widget(&nolock_settings_->village_support_slider_, xpos_right, ypos_right);
|
||||
ypos_right += nolock_settings_->village_support_slider_.height() + border_size;
|
||||
|
||||
options_pane_right_.add_widget(&nolock_settings_->village_gold_label_, xpos_right, ypos_right);
|
||||
ypos_right += nolock_settings_->village_gold_label_.height() + border_size;
|
||||
nolock_settings_->village_gold_slider_.set_width(slider_width);
|
||||
|
||||
options_pane_right_.add_widget(&nolock_settings_->village_gold_slider_, xpos_right, ypos_right);
|
||||
ypos_right += nolock_settings_->village_gold_slider_.height() + 3 * border_size;
|
||||
|
||||
}
|
||||
|
||||
options_manager_.layout_widgets(xpos_right, ypos_right, column_width);
|
||||
|
||||
// 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.x + ca.w - right_button->width(),
|
||||
ca.y + ca.h - right_button->height());
|
||||
left_button->set_location(right_button->location().x - left_button->width() -
|
||||
gui::ButtonHPadding, ca.y + ca.h - left_button->height());
|
||||
}
|
||||
|
||||
} // namespace mp
|
||||
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2013 - 2016 Boldizsár Lipka <lipkab@zoho.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_CONFIGURE_HPP_INCLUDED
|
||||
#define MULTIPLAYER_CONFIGURE_HPP_INCLUDED
|
||||
|
||||
#include "depcheck.hpp"
|
||||
#include "mp_game_settings.hpp"
|
||||
#include "multiplayer_ui.hpp"
|
||||
#include "widgets/slider.hpp"
|
||||
#include "widgets/scrollpane.hpp"
|
||||
#include "widgets/combo.hpp"
|
||||
#include "tooltips.hpp"
|
||||
#include "mp_options.hpp"
|
||||
#include "configure_engine.hpp"
|
||||
|
||||
class saved_game;
|
||||
namespace mp {
|
||||
|
||||
class configure : public mp::ui
|
||||
{
|
||||
public:
|
||||
///gives the user the option to adjust the passed saved_game
|
||||
///Call get_parameters to finalize;
|
||||
configure(CVideo& v, wesnothd_connection* connection, const config& game_config, chat& c, config& gamelist, saved_game& game, bool local_players_only);
|
||||
~configure();
|
||||
|
||||
void get_parameters();
|
||||
protected:
|
||||
virtual void layout_children(const SDL_Rect& rect);
|
||||
virtual void process_event();
|
||||
virtual void hide_children(bool hide=true);
|
||||
|
||||
private:
|
||||
//Settings that can be changed unledd wml forbids it
|
||||
struct nolock_settings
|
||||
{
|
||||
nolock_settings(CVideo& video);
|
||||
|
||||
gui::slider turns_slider_;
|
||||
gui::label turns_label_;
|
||||
gui::slider village_gold_slider_;
|
||||
gui::label village_gold_label_;
|
||||
gui::slider village_support_slider_;
|
||||
gui::label village_support_label_;
|
||||
gui::slider xp_modifier_slider_;
|
||||
gui::label xp_modifier_label_;
|
||||
gui::label generic_label_;
|
||||
gui::button use_map_settings_;
|
||||
gui::button random_start_time_;
|
||||
gui::button fog_game_;
|
||||
gui::button shroud_game_;
|
||||
};
|
||||
bool local_players_only_;
|
||||
|
||||
tooltips::manager tooltip_manager_;
|
||||
int mp_countdown_init_time_;
|
||||
int mp_countdown_reservoir_time_;
|
||||
|
||||
gui::button countdown_game_;
|
||||
gui::slider countdown_init_time_slider_;
|
||||
gui::label countdown_init_time_label_;
|
||||
gui::slider countdown_reservoir_time_slider_;
|
||||
gui::label countdown_reservoir_time_label_;
|
||||
gui::label countdown_turn_bonus_label_;
|
||||
gui::slider countdown_turn_bonus_slider_;
|
||||
gui::label countdown_action_bonus_label_;
|
||||
gui::slider countdown_action_bonus_slider_;
|
||||
|
||||
gui::label name_entry_label_;
|
||||
gui::button observers_game_;
|
||||
gui::button registered_users_only_;
|
||||
gui::button oos_debug_;
|
||||
gui::button shuffle_sides_;
|
||||
gui::label random_faction_mode_label_;
|
||||
gui::combo random_faction_mode_;
|
||||
|
||||
gui::button cancel_game_;
|
||||
gui::button launch_game_;
|
||||
gui::button password_button_;
|
||||
|
||||
gui::textbox name_entry_;
|
||||
|
||||
gui::label entry_points_label_;
|
||||
gui::combo entry_points_combo_;
|
||||
|
||||
gui::scrollpane options_pane_left_;
|
||||
gui::scrollpane options_pane_right_;
|
||||
|
||||
std::vector<config const*> entry_points_;
|
||||
bool show_entry_points_;
|
||||
|
||||
bool force_use_map_settings_check_;
|
||||
saved_game& state_;
|
||||
mp_game_settings& parameters_;
|
||||
ng::configure_engine engine_;
|
||||
options::manager options_manager_;
|
||||
|
||||
const std::unique_ptr<nolock_settings> nolock_settings_;
|
||||
struct process_event_data {
|
||||
bool launch, quit;
|
||||
|
||||
process_event_data()
|
||||
: launch(false), quit(false)
|
||||
{}
|
||||
process_event_data(bool l, bool q)
|
||||
: launch(l), quit(q)
|
||||
{}
|
||||
};
|
||||
|
||||
void process_event_impl(const process_event_data &);
|
||||
bool plugin_event_helper(const process_event_data &);
|
||||
};
|
||||
|
||||
} // end namespace mp
|
||||
|
||||
#endif
|
|
@ -1,612 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 - 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
|
||||
* Prepare to join a multiplayer-game.
|
||||
*/
|
||||
#include "game_initialization/multiplayer_connect.hpp"
|
||||
|
||||
#include "ai/configuration.hpp"
|
||||
#include "construct_dialog.hpp"
|
||||
#include "display_chat_manager.hpp"
|
||||
#include "font/standard_colors.hpp"
|
||||
#include "game_preferences.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "map/map.hpp"
|
||||
#include "mp_ui_alerts.hpp"
|
||||
#include "scripting/plugins/context.hpp"
|
||||
#include "wml_separators.hpp"
|
||||
|
||||
#include "utils/functional.hpp"
|
||||
|
||||
static lg::log_domain log_mp_connect("mp/connect");
|
||||
#define DBG_MP LOG_STREAM(debug, log_mp_connect)
|
||||
#define LOG_MP LOG_STREAM(info, log_mp_connect)
|
||||
|
||||
namespace mp {
|
||||
|
||||
std::vector<std::string> controller_options_names(
|
||||
const std::vector<ng::controller_option>& controller_options)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
for (const ng::controller_option& option : controller_options) {
|
||||
names.push_back(option.second);
|
||||
}
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
static std::string get_income_string(int income)
|
||||
{
|
||||
|
||||
std::stringstream buf;
|
||||
if (income < 0) {
|
||||
buf << _("(") << income << _(")");
|
||||
} else if (income > 0) {
|
||||
buf << _("+") << income;
|
||||
} else {
|
||||
buf << _("Normal");
|
||||
}
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
connect::side::side(connect& parent, ng::side_engine_ptr engine) :
|
||||
parent_(&parent),
|
||||
engine_(engine),
|
||||
gold_lock_(engine_->cfg()["gold_lock"].to_bool(
|
||||
parent_->force_lock_settings())),
|
||||
income_lock_(engine_->cfg()["income_lock"].to_bool(
|
||||
parent_->force_lock_settings())),
|
||||
team_lock_(engine_->cfg()["team_lock"].to_bool(
|
||||
parent_->force_lock_settings())),
|
||||
color_lock_(engine_->cfg()["color_lock"].to_bool(
|
||||
parent_->force_lock_settings())),
|
||||
changed_(false),
|
||||
label_player_number_(parent.video(), std::to_string(engine_->index() + 1),
|
||||
font::SIZE_LARGE, font::LOBBY_COLOR),
|
||||
label_original_controller_(parent.video(), engine_->reserved_for(),
|
||||
font::SIZE_SMALL),
|
||||
label_gold_(parent.video(), std::to_string(engine_->gold()), font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
label_income_(parent.video(), get_income_string(engine_->income()), font::SIZE_SMALL,
|
||||
font::LOBBY_COLOR),
|
||||
combo_controller_(new gui::combo_drag(parent.video(),
|
||||
std::vector<std::string>(), parent.combo_control_group_)),
|
||||
combo_ai_algorithm_(parent.video(), std::vector<std::string>()),
|
||||
combo_faction_(parent.video(), std::vector<std::string>()),
|
||||
label_leader_name_(parent.video(), engine_->cfg()["name"], font::SIZE_SMALL),
|
||||
combo_leader_(parent.video(), std::vector<std::string>()),
|
||||
combo_gender_(parent.video(), std::vector<std::string>()),
|
||||
combo_team_(parent.video(), engine_->player_teams()),
|
||||
combo_color_(parent.video(), engine->get_colors()),
|
||||
slider_gold_(parent.video()),
|
||||
slider_income_(parent.video())
|
||||
{
|
||||
DBG_MP << "initializing side" << std::endl;
|
||||
|
||||
slider_gold_.set_min(20);
|
||||
slider_gold_.set_max(800);
|
||||
slider_gold_.set_increment(25);
|
||||
slider_gold_.set_value(engine_->cfg()["gold"].to_int(100));
|
||||
slider_gold_.set_measurements(80, 16);
|
||||
|
||||
slider_income_.set_min(-2);
|
||||
slider_income_.set_max(18);
|
||||
slider_income_.set_increment(1);
|
||||
slider_income_.set_value(engine_->cfg()["income"]);
|
||||
slider_income_.set_measurements(50, 16);
|
||||
|
||||
combo_faction_.enable(!parent_->params().saved_game);
|
||||
combo_leader_.enable(!parent_->params().saved_game);
|
||||
combo_gender_.enable(!parent_->params().saved_game);
|
||||
combo_team_.enable(!parent_->params().saved_game);
|
||||
combo_color_.enable(!parent_->params().saved_game);
|
||||
slider_gold_.hide(parent_->params().saved_game);
|
||||
slider_income_.hide(parent_->params().saved_game);
|
||||
label_gold_.hide(parent_->params().saved_game);
|
||||
label_income_.hide(parent_->params().saved_game);
|
||||
|
||||
if (parent_->params().use_map_settings) {
|
||||
// Gold, income, team, and color are only suggestions.
|
||||
// (Unless explicitly locked).
|
||||
slider_gold_.enable(!gold_lock_);
|
||||
label_gold_.enable(!gold_lock_);
|
||||
slider_income_.enable(!income_lock_);
|
||||
label_income_.enable(!income_lock_);
|
||||
combo_team_.enable(!team_lock_);
|
||||
combo_color_.enable(!color_lock_);
|
||||
}
|
||||
|
||||
update_ui();
|
||||
}
|
||||
|
||||
connect::side::side(const side& a) :
|
||||
parent_(a.parent_),
|
||||
engine_(a.engine_),
|
||||
gold_lock_(a.gold_lock_),
|
||||
income_lock_(a.income_lock_),
|
||||
team_lock_(a.team_lock_),
|
||||
color_lock_(a.color_lock_),
|
||||
changed_(a.changed_),
|
||||
label_player_number_(a.label_player_number_),
|
||||
label_original_controller_(a.label_original_controller_),
|
||||
label_gold_(a.label_gold_),
|
||||
label_income_(a.label_income_),
|
||||
combo_controller_(a.combo_controller_),
|
||||
combo_ai_algorithm_(a.combo_ai_algorithm_),
|
||||
combo_faction_(a.combo_faction_),
|
||||
label_leader_name_(a.label_leader_name_),
|
||||
combo_leader_(a.combo_leader_),
|
||||
combo_gender_(a.combo_gender_),
|
||||
combo_team_(a.combo_team_),
|
||||
combo_color_(a.combo_color_),
|
||||
slider_gold_(a.slider_gold_),
|
||||
slider_income_(a.slider_income_)
|
||||
{
|
||||
}
|
||||
|
||||
connect::side::~side()
|
||||
{
|
||||
}
|
||||
|
||||
void connect::side::process_event()
|
||||
{
|
||||
int drop_target;
|
||||
if ((drop_target = combo_controller_->get_drop_target()) > -1) {
|
||||
if (engine_->swap_sides_on_drop_target(drop_target)) {
|
||||
changed_ = true;
|
||||
parent_->sides_[drop_target].changed_ = true;
|
||||
|
||||
update_ui();
|
||||
parent_->sides_[drop_target].update_ui();
|
||||
}
|
||||
} else if (combo_controller_->changed() &&
|
||||
combo_controller_->selected() >= 0) {
|
||||
|
||||
changed_ = engine_->controller_changed(combo_controller_->selected());
|
||||
update_controller_ui();
|
||||
}
|
||||
if (combo_controller_->hidden()) {
|
||||
combo_controller_->hide(false);
|
||||
}
|
||||
|
||||
if (parent_->params().saved_game) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (combo_color_.changed() && combo_color_.selected() >= 0) {
|
||||
engine_->set_color(combo_color_.selected());
|
||||
update_faction_combo();
|
||||
engine_->flg().reset_leader_combo(combo_leader_, engine_->get_color());
|
||||
engine_->flg().reset_gender_combo(combo_gender_, engine_->get_color());
|
||||
changed_ = true;
|
||||
}
|
||||
if (combo_faction_.changed() && combo_faction_.selected() >= 0) {
|
||||
engine_->flg().set_current_faction(combo_faction_.selected());
|
||||
engine_->flg().reset_leader_combo(combo_leader_, engine_->get_color());
|
||||
engine_->flg().reset_gender_combo(combo_gender_, engine_->get_color());
|
||||
changed_ = true;
|
||||
}
|
||||
if (combo_ai_algorithm_.changed() && combo_ai_algorithm_.selected() >= 0) {
|
||||
engine_->set_ai_algorithm(
|
||||
parent_->ai_algorithms_[combo_ai_algorithm_.selected()]->id);
|
||||
changed_ = true;
|
||||
}
|
||||
if (combo_leader_.changed() && combo_leader_.selected() >= 0) {
|
||||
engine_->flg().set_current_leader(combo_leader_.selected());
|
||||
engine_->flg().reset_gender_combo(combo_gender_, engine_->get_color());
|
||||
changed_ = true;
|
||||
}
|
||||
if (combo_gender_.changed() && combo_gender_.selected() >= 0) {
|
||||
engine_->flg().set_current_gender(combo_gender_.selected());
|
||||
changed_ = true;
|
||||
}
|
||||
if (combo_team_.changed() && combo_team_.selected() >= 0) {
|
||||
engine_->set_team(combo_team_.selected());
|
||||
changed_ = true;
|
||||
}
|
||||
if (slider_gold_.value() != engine_->gold() && slider_gold_.enabled()) {
|
||||
engine_->set_gold(slider_gold_.value());
|
||||
changed_ = true;
|
||||
label_gold_.set_text(std::to_string(engine_->gold()));
|
||||
}
|
||||
if (slider_income_.value() != engine_->income() && slider_income_.enabled()) {
|
||||
engine_->set_income(slider_income_.value());
|
||||
changed_ = true;
|
||||
label_income_.set_text(get_income_string(engine_->income()));
|
||||
}
|
||||
}
|
||||
|
||||
bool connect::side::changed()
|
||||
{
|
||||
if (changed_) {
|
||||
changed_ = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void connect::side::update_ui()
|
||||
{
|
||||
update_faction_combo();
|
||||
engine_->flg().reset_leader_combo(combo_leader_, engine_->get_color());
|
||||
engine_->flg().reset_gender_combo(combo_gender_, engine_->get_color());
|
||||
|
||||
update_controller_ui();
|
||||
|
||||
combo_team_.set_selected(engine_->team());
|
||||
combo_color_.set_selected(engine_->color());
|
||||
slider_gold_.set_value(engine_->gold());
|
||||
label_gold_.set_text(std::to_string(engine_->gold()));
|
||||
slider_income_.set_value(engine_->income());
|
||||
std::stringstream buf;
|
||||
if (engine_->income() < 0) {
|
||||
buf << _("(") << engine_->income() << _(")");
|
||||
} else if (engine_->income() > 0) {
|
||||
buf << _("+") << engine_->income();
|
||||
} else {
|
||||
buf << _("Normal");
|
||||
}
|
||||
label_income_.set_text(buf.str());
|
||||
}
|
||||
|
||||
void connect::side::add_widgets_to_scrollpane(gui::scrollpane& pane, int pos)
|
||||
{
|
||||
// Offset value to align labels in y-axis.
|
||||
int label_y_offset = (combo_leader_.height() - label_leader_name_.height()) / 2;
|
||||
|
||||
pane.add_widget(&label_player_number_, 0, 5 + pos);
|
||||
|
||||
pane.add_widget(combo_controller_.get(), 20, 5 + pos);
|
||||
pane.add_widget(&label_original_controller_, 20 +
|
||||
(combo_controller_->width() - label_original_controller_.width()) / 2,
|
||||
35 + pos + label_y_offset);
|
||||
pane.add_widget(&combo_ai_algorithm_, 20, 35 + pos);
|
||||
|
||||
pane.add_widget(&combo_faction_, 135, 5 + pos);
|
||||
pane.add_widget(&label_leader_name_, 135 +
|
||||
(combo_faction_.width() - label_leader_name_.width()) / 2,
|
||||
35 + pos + label_y_offset);
|
||||
|
||||
pane.add_widget(&combo_leader_, 250, 5 + pos);
|
||||
pane.add_widget(&combo_gender_, 250, 35 + pos);
|
||||
|
||||
pane.add_widget(&combo_team_, 365, 5 + pos);
|
||||
pane.add_widget(&combo_color_, 365, 35 + pos);
|
||||
|
||||
pane.add_widget(&slider_gold_, 475, 5 + pos);
|
||||
pane.add_widget(&label_gold_, 475 + 5, 35 + pos + label_y_offset);
|
||||
|
||||
pane.add_widget(&slider_income_, 475 + slider_gold_.width(), 5 + pos);
|
||||
pane.add_widget(&label_income_, 475 + 5 + slider_gold_.width(),
|
||||
35 + pos + label_y_offset);
|
||||
}
|
||||
|
||||
void connect::side::update_faction_combo()
|
||||
{
|
||||
std::vector<std::string> factions;
|
||||
for (const config* faction : engine_->flg().choosable_factions()) {
|
||||
const std::string& name = (*faction)["name"];
|
||||
const std::string& icon = (*faction)["image"];
|
||||
if (!icon.empty()) {
|
||||
std::string rgb = (*faction)["flag_rgb"];
|
||||
if (rgb.empty()) {
|
||||
rgb = "magenta";
|
||||
}
|
||||
factions.push_back(IMAGE_PREFIX + icon + "~RC(" + rgb + ">" + engine_->get_color() + ")" + COLUMN_SEPARATOR + name);
|
||||
} else {
|
||||
factions.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
combo_faction_.enable(factions.size() > 1 && !parent_->params().saved_game);
|
||||
|
||||
combo_faction_.set_items(factions);
|
||||
combo_faction_.set_selected(engine_->flg().current_faction_index());
|
||||
}
|
||||
|
||||
void connect::side::update_controller_ui()
|
||||
{
|
||||
// Update controllers combo.
|
||||
combo_controller_->set_items(controller_options_names(
|
||||
engine_->controller_options()));
|
||||
combo_controller_->set_selected(engine_->current_controller_index());
|
||||
combo_controller_->enable(engine_->controller_options().size() > 1);
|
||||
|
||||
// Update AI algorithm combo.
|
||||
assert(!parent_->ai_algorithms_.empty());
|
||||
int sel = 0;
|
||||
int i = 0;
|
||||
std::vector<std::string> ais;
|
||||
for (const ai::description* desc : parent_->ai_algorithms_) {
|
||||
ais.push_back(desc->text);
|
||||
if (desc->id == engine_->ai_algorithm()) {
|
||||
sel = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
combo_ai_algorithm_.set_items(ais);
|
||||
combo_ai_algorithm_.set_selected(sel);
|
||||
// Ensures that the visually selected AI
|
||||
// is the one that will be loaded.
|
||||
engine_->set_ai_algorithm(parent_->ai_algorithms_[sel]->id);
|
||||
|
||||
// Adjust the visibility of AI algorithm combo
|
||||
// and original controller label.
|
||||
if (!parent_->hidden()) {
|
||||
if (engine_->controller() == ng::CNTR_COMPUTER) {
|
||||
// Computer selected, show AI combo.
|
||||
combo_ai_algorithm_.hide(false);
|
||||
|
||||
label_original_controller_.hide(true);
|
||||
} else {
|
||||
// Computer de-selected, hide AI combo.
|
||||
combo_ai_algorithm_.hide(true);
|
||||
|
||||
label_original_controller_.hide(false);
|
||||
label_original_controller_.set_text(engine_->reserved_for());
|
||||
}
|
||||
} else {
|
||||
combo_ai_algorithm_.hide(true);
|
||||
}
|
||||
}
|
||||
|
||||
connect::connect(CVideo& v, wesnothd_connection* connection, const std::string& game_name,
|
||||
const config& game_config, chat& c, config& gamelist,
|
||||
ng::connect_engine& engine) :
|
||||
mp::ui(v, connection, _("Game Lobby: ") + game_name, game_config, c, gamelist),
|
||||
ai_algorithms_(),
|
||||
sides_(),
|
||||
engine_(engine),
|
||||
waiting_label_(video(), "", font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
type_title_label_(video(), _("Player/Type"), font::SIZE_SMALL,
|
||||
font::LOBBY_COLOR),
|
||||
faction_name_title_label_(video(), _("Faction/Name"), font::SIZE_SMALL,
|
||||
font::LOBBY_COLOR),
|
||||
leader_gender_title_label_(video(), _("Leader/Gender"), font::SIZE_SMALL,
|
||||
font::LOBBY_COLOR),
|
||||
team_color_title_label_(video(), _("Team/Color"), font::SIZE_SMALL,
|
||||
font::LOBBY_COLOR),
|
||||
gold_title_label_(video(), _("Gold"), font::SIZE_SMALL,
|
||||
font::LOBBY_COLOR),
|
||||
income_title_label_(video(), _("Income"), font::SIZE_SMALL,
|
||||
font::LOBBY_COLOR),
|
||||
scroll_pane_(video()),
|
||||
launch_(video(), _("I’m Ready")),
|
||||
cancel_(video(), engine_.first_scenario() ? _("Cancel") : _("Quit")),
|
||||
combo_control_group_(new gui::drop_group_manager())
|
||||
{
|
||||
DBG_MP << "setting up connect dialog" << std::endl;
|
||||
|
||||
// Load game exception occured.
|
||||
if (engine_.level().empty()) {
|
||||
set_result(CREATE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (get_result() == QUIT || get_result() == CREATE) {
|
||||
return;
|
||||
}
|
||||
if (engine_.scenario()["id"].empty()) {
|
||||
throw config::error(_("The scenario is invalid because it has no id."));
|
||||
}
|
||||
|
||||
ai_algorithms_ = ai::configuration::get_available_ais();
|
||||
|
||||
// Sides.
|
||||
for (ng::side_engine_ptr s : engine_.side_engines()) {
|
||||
sides_.push_back(side(*this, s));
|
||||
}
|
||||
if (sides_.empty() && !game_config::debug) {
|
||||
throw config::error(
|
||||
_("The scenario is invalid because it has no sides."));
|
||||
}
|
||||
|
||||
// Add side widgets to scroll pane.
|
||||
int side_pos_y_offset = 0;
|
||||
for (side& s : sides_) {
|
||||
if (!s.engine()->allow_player() && !game_config::debug) {
|
||||
continue;
|
||||
}
|
||||
|
||||
s.add_widgets_to_scrollpane(scroll_pane_, side_pos_y_offset);
|
||||
side_pos_y_offset += 60;
|
||||
}
|
||||
|
||||
append_to_title(" — " + engine_.scenario()["name"].t_str());
|
||||
gold_title_label_.hide(params().saved_game);
|
||||
income_title_label_.hide(params().saved_game);
|
||||
|
||||
update_playerlist_state(true);
|
||||
|
||||
plugins_context_.reset(new plugins_context("Multiplayer Connect"));
|
||||
|
||||
//These structure initializers create a lobby::process_data_event
|
||||
plugins_context_->set_callback("launch", std::bind(&connect::plugin_event_helper, this, process_event_data (true, false)));
|
||||
plugins_context_->set_callback("quit", std::bind(&connect::plugin_event_helper, this, process_event_data (false, true)));
|
||||
plugins_context_->set_callback("chat", [this](const config& cfg) { send_chat_message(cfg["message"], false); }, true);
|
||||
}
|
||||
|
||||
connect::~connect()
|
||||
{
|
||||
}
|
||||
|
||||
bool connect::plugin_event_helper(const process_event_data & data)
|
||||
{
|
||||
process_event_impl(data);
|
||||
return get_result() == mp::ui::CONTINUE;
|
||||
}
|
||||
|
||||
void connect::process_event()
|
||||
{
|
||||
process_event_data data;
|
||||
data.quit = cancel_.pressed();
|
||||
data.launch = launch_.pressed();
|
||||
|
||||
process_event_impl(data);
|
||||
}
|
||||
|
||||
void connect::process_event_impl(const process_event_data & data)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
for (side& s : sides_) {
|
||||
s.process_event();
|
||||
if (s.changed()) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.quit) {
|
||||
if (wesnothd_connection_) {
|
||||
config cfg;
|
||||
cfg.add_child("leave_game");
|
||||
send_to_server(cfg);
|
||||
}
|
||||
|
||||
set_result(QUIT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.launch) {
|
||||
if (engine_.can_start_game()) {
|
||||
set_result(mp::ui::PLAY);
|
||||
}
|
||||
}
|
||||
|
||||
// If something has changed in the level config,
|
||||
// send it to the network.
|
||||
if (changed) {
|
||||
update_playerlist_state();
|
||||
engine_.update_and_send_diff();
|
||||
}
|
||||
}
|
||||
|
||||
void connect::hide_children(bool hide)
|
||||
{
|
||||
DBG_MP << (hide ? "hiding" : "showing" ) <<
|
||||
" children widgets" << std::endl;
|
||||
|
||||
ui::hide_children(hide);
|
||||
|
||||
waiting_label_.hide(hide);
|
||||
scroll_pane_.hide(hide); // Scroll pane contents are automatically hidden.
|
||||
|
||||
faction_name_title_label_.hide(hide);
|
||||
leader_gender_title_label_.hide(hide);
|
||||
team_color_title_label_.hide(hide);
|
||||
|
||||
if (!params().saved_game) {
|
||||
gold_title_label_.hide(hide);
|
||||
income_title_label_.hide(hide);
|
||||
}
|
||||
|
||||
launch_.hide(hide);
|
||||
cancel_.hide(hide);
|
||||
}
|
||||
|
||||
void connect::layout_children(const SDL_Rect& rect)
|
||||
{
|
||||
ui::layout_children(rect);
|
||||
|
||||
SDL_Rect ca = client_area();
|
||||
|
||||
gui::button* left_button = &launch_;
|
||||
gui::button* right_button = &cancel_;
|
||||
#ifdef OK_BUTTON_ON_RIGHT
|
||||
std::swap(left_button,right_button);
|
||||
#endif
|
||||
size_t left = ca.x;
|
||||
size_t right = ca.x + ca.w;
|
||||
size_t top = ca.y;
|
||||
size_t bottom = ca.y + ca.h;
|
||||
|
||||
// Buttons.
|
||||
right_button->set_location(right - right_button->width(),
|
||||
bottom - right_button->height());
|
||||
left_button->set_location(right - right_button->width() -
|
||||
left_button->width()- gui::ButtonHPadding, bottom -
|
||||
left_button->height());
|
||||
|
||||
type_title_label_.set_location(left + 30, top + 35);
|
||||
faction_name_title_label_.set_location((left + 145), top + 35);
|
||||
leader_gender_title_label_.set_location((left + 260), top + 35);
|
||||
team_color_title_label_.set_location((left + 375), top + 35);
|
||||
gold_title_label_.set_location((left + 493), top + 35);
|
||||
income_title_label_.set_location((left + 560), top + 35);
|
||||
|
||||
waiting_label_.set_location(left + gui::ButtonHPadding,
|
||||
bottom - left_button->height() + 4);
|
||||
|
||||
SDL_Rect scroll_pane_rect;
|
||||
scroll_pane_rect.x = ca.x;
|
||||
scroll_pane_rect.y = ca.y + 50;
|
||||
scroll_pane_rect.w = ca.w;
|
||||
scroll_pane_rect.h = launch_.location().y - scroll_pane_rect.y -
|
||||
gui::ButtonVPadding;
|
||||
|
||||
scroll_pane_.set_location(scroll_pane_rect);
|
||||
}
|
||||
|
||||
void connect::process_network_data(const config& data)
|
||||
{
|
||||
ui::process_network_data(data);
|
||||
|
||||
bool was_able_to_start = engine_.can_start_game();
|
||||
std::pair<bool, bool> result = engine_.process_network_data(data);
|
||||
|
||||
if (result.first) {
|
||||
set_result(QUIT);
|
||||
}
|
||||
|
||||
for (side& s : sides_) {
|
||||
s.update_ui();
|
||||
}
|
||||
|
||||
update_playerlist_state(result.second); //result.second is the silent flag
|
||||
if (!was_able_to_start && engine_.can_start_game()) {
|
||||
DBG_MP << "play party full sound" << std::endl;
|
||||
mp_ui_alerts::ready_for_start();
|
||||
}
|
||||
}
|
||||
|
||||
void connect::update_playerlist_state(bool silent)
|
||||
{
|
||||
DBG_MP << "updating player list state" << std::endl;
|
||||
|
||||
waiting_label_.set_text(engine_.can_start_game() ? ""
|
||||
: engine_.sides_available()
|
||||
? _("Waiting for players to join...")
|
||||
: _("Waiting for players to choose factions..."));
|
||||
launch_.enable(engine_.can_start_game());
|
||||
|
||||
// If the "gamelist_" variable has users, use it.
|
||||
// Else, extracts the user list from the actual player list.
|
||||
if (gamelist().child("user")) {
|
||||
ui::gamelist_updated(silent);
|
||||
} else {
|
||||
// Updates the player list
|
||||
std::vector<std::string> playerlist;
|
||||
for (const std::string& user : engine_.connected_users()) {
|
||||
playerlist.push_back(user);
|
||||
}
|
||||
set_user_list(playerlist, silent);
|
||||
set_user_menu_items(playerlist);
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace mp
|
||||
|
|
@ -1,160 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 - 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 */
|
||||
|
||||
#ifndef MULTIPLAYER_CONNECT_H_INCLUDED
|
||||
#define MULTIPLAYER_CONNECT_H_INCLUDED
|
||||
|
||||
#include "commandline_options.hpp"
|
||||
#include "connect_engine.hpp"
|
||||
#include "multiplayer_ui.hpp"
|
||||
#include "widgets/combo_drag.hpp"
|
||||
#include "widgets/scrollpane.hpp"
|
||||
#include "widgets/slider.hpp"
|
||||
class CVideo;
|
||||
|
||||
namespace ai {
|
||||
struct description;
|
||||
}
|
||||
|
||||
namespace mp {
|
||||
|
||||
// Helper function to retrieve controller names.
|
||||
std::vector<std::string> controller_options_names(
|
||||
const std::vector<ng::controller_option>& controller_options);
|
||||
|
||||
class connect : public mp::ui
|
||||
{
|
||||
public:
|
||||
|
||||
class side {
|
||||
public:
|
||||
side(connect& parent, ng::side_engine_ptr engine);
|
||||
side(const side& a);
|
||||
~side();
|
||||
|
||||
void process_event();
|
||||
|
||||
// Returns true if this side changed since last call to this method.
|
||||
bool changed();
|
||||
|
||||
void update_ui();
|
||||
|
||||
void add_widgets_to_scrollpane(gui::scrollpane& pane, int pos);
|
||||
|
||||
ng::side_engine_ptr engine() { return engine_; }
|
||||
const ng::side_engine_ptr engine() const { return engine_; }
|
||||
|
||||
private:
|
||||
// Update UI methods and their helper(s).
|
||||
void update_faction_combo();
|
||||
void update_controller_ui();
|
||||
|
||||
// The mp::connect widget owning this mp::connect::side.
|
||||
connect* parent_;
|
||||
ng::side_engine_ptr engine_;
|
||||
|
||||
// Flags for controlling which configuration widgets should be locked.
|
||||
bool gold_lock_;
|
||||
bool income_lock_;
|
||||
bool team_lock_;
|
||||
bool color_lock_;
|
||||
|
||||
bool changed_;
|
||||
|
||||
gui::label label_player_number_;
|
||||
gui::label label_original_controller_;
|
||||
gui::label label_gold_;
|
||||
gui::label label_income_;
|
||||
gui::combo_drag_ptr combo_controller_;
|
||||
gui::combo combo_ai_algorithm_;
|
||||
gui::combo combo_faction_;
|
||||
gui::label label_leader_name_;
|
||||
gui::combo combo_leader_;
|
||||
gui::combo combo_gender_;
|
||||
gui::combo combo_team_;
|
||||
gui::combo combo_color_;
|
||||
gui::slider slider_gold_;
|
||||
gui::slider slider_income_;
|
||||
};
|
||||
|
||||
typedef std::vector<side> side_list;
|
||||
|
||||
connect(CVideo& v, wesnothd_connection* connection, const std::string& game_name,
|
||||
const config& game_config, chat& c, config& gamelist,
|
||||
ng::connect_engine& engine);
|
||||
~connect();
|
||||
|
||||
// Updates the current game state, resolves random factions, and sends a
|
||||
// "start game" message to the network.
|
||||
void start_game() { engine_.start_game(); }
|
||||
void start_game_commandline(const commandline_options& cmdline_opts)
|
||||
{ engine_.start_game_commandline(cmdline_opts); }
|
||||
|
||||
protected:
|
||||
virtual void process_event();
|
||||
|
||||
virtual void layout_children(const SDL_Rect& rect);
|
||||
virtual void hide_children(bool hide = true);
|
||||
|
||||
virtual void process_network_data(const config& data);
|
||||
|
||||
private:
|
||||
connect(const connect&);
|
||||
void operator=(const connect&);
|
||||
|
||||
// Updates the state of the player list, the launch button and of the start
|
||||
// game label, to reflect the actual state.
|
||||
void update_playerlist_state(bool silent = true);
|
||||
|
||||
const mp_game_settings& params() { return engine_.params(); }
|
||||
bool force_lock_settings() const { return engine_.force_lock_settings(); }
|
||||
|
||||
std::vector<ai::description*> ai_algorithms_;
|
||||
|
||||
side_list sides_;
|
||||
ng::connect_engine& engine_;
|
||||
|
||||
gui::label waiting_label_;
|
||||
gui::label type_title_label_;
|
||||
gui::label faction_name_title_label_;
|
||||
gui::label leader_gender_title_label_;
|
||||
gui::label team_color_title_label_;
|
||||
gui::label gold_title_label_;
|
||||
gui::label income_title_label_;
|
||||
gui::scrollpane scroll_pane_;
|
||||
gui::button launch_;
|
||||
gui::button cancel_;
|
||||
gui::drop_group_manager_ptr combo_control_group_;
|
||||
|
||||
struct process_event_data {
|
||||
bool launch, quit;
|
||||
|
||||
process_event_data()
|
||||
: launch(false), quit(false)
|
||||
{}
|
||||
process_event_data(bool l, bool q)
|
||||
: launch(l), quit(q)
|
||||
{}
|
||||
};
|
||||
|
||||
void process_event_impl(const process_event_data &);
|
||||
bool plugin_event_helper(const process_event_data &);
|
||||
};
|
||||
|
||||
} // end namespace mp
|
||||
|
||||
#endif
|
||||
|
|
@ -1,783 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 - 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
|
||||
* Create a multiplayer-game: select map, players, options etc.
|
||||
*/
|
||||
|
||||
#include "global.hpp"
|
||||
|
||||
#include "gettext.hpp"
|
||||
#include "game_config_manager.hpp"
|
||||
#include "video.hpp"
|
||||
#include "game_preferences.hpp"
|
||||
#include "config_assign.hpp"
|
||||
#include "construct_dialog.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "map/map.hpp"
|
||||
#include "map/exception.hpp"
|
||||
#include "generators/map_create.hpp"
|
||||
#include "gui/dialogs/message.hpp"
|
||||
#include "gui/dialogs/campaign_difficulty.hpp"
|
||||
#include "gui/dialogs/multiplayer/mp_create_game_set_password.hpp"
|
||||
#include "gui/dialogs/transient_message.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "minimap.hpp"
|
||||
#include "game_initialization/multiplayer_create.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include "scripting/plugins/context.hpp"
|
||||
#include "log.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
#include "wml_separators.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "widgets/multimenu.hpp"
|
||||
#include "sdl/utils.hpp"
|
||||
#include "sdl/rect.hpp"
|
||||
#include "font/standard_colors.hpp"
|
||||
|
||||
#include "utils/functional.hpp"
|
||||
|
||||
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 {
|
||||
const SDL_Rect null_rect = {0, 0, 0, 0};
|
||||
}
|
||||
|
||||
namespace mp {
|
||||
|
||||
static config get_selected_helper(const ng::create_engine * eng_ptr)
|
||||
{
|
||||
assert(eng_ptr);
|
||||
const ng::create_engine & eng = *eng_ptr;
|
||||
return config_of("id", eng.current_level().id())
|
||||
("name", eng.current_level().name())
|
||||
("icon", eng.current_level().icon())
|
||||
("description", eng.current_level().description())
|
||||
("allow_era_choice", eng.current_level().allow_era_choice())
|
||||
("type", eng.current_level_type());
|
||||
}
|
||||
|
||||
static config find_helper(const ng::create_engine * eng_ptr, const config & cfg)
|
||||
{
|
||||
assert(eng_ptr);
|
||||
const ng::create_engine & eng = *eng_ptr;
|
||||
std::string str = cfg["id"].str();
|
||||
|
||||
return config_of("index", eng.find_level_by_id(str))("type", eng.find_level_type_by_id(str));
|
||||
}
|
||||
|
||||
create::create(CVideo& video, wesnothd_connection* connection, const config& cfg, saved_game& state, chat& c, config& gamelist) :
|
||||
ui(video, connection, _("Create Game"), cfg, c, gamelist),
|
||||
tooltip_manager_(video),
|
||||
era_selection_(-1),
|
||||
mod_selection_(-1),
|
||||
level_selection_(-1),
|
||||
eras_menu_(video, std::vector<std::string>()),
|
||||
levels_menu_(video, std::vector<std::string>()),
|
||||
mods_menu_(video, std::vector<std::string>()),
|
||||
filter_name_label_(video, _("Filter:"), font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
filter_num_players_label_(video, _("Number of players: any"), font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
map_generator_label_(video, _("Random map options:"), font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
era_label_(video, _("Era:"), font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
no_era_label_(video, _("No eras available\nfor this game."),
|
||||
font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
mod_label_(video, _("Modifications:"), font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
map_size_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
num_players_label_(video, "", font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
level_type_label_(video, "Game type:", font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
launch_game_(video, _("Next")),
|
||||
cancel_game_(video, _("Cancel")),
|
||||
regenerate_map_(video, _("Regenerate")),
|
||||
generator_settings_(video, _("Settings...")),
|
||||
load_game_(video, _("Load Game...")),
|
||||
level_type_combo_(video, std::vector<std::string>()),
|
||||
filter_num_players_slider_(video),
|
||||
description_(video, 100, "", false),
|
||||
filter_name_(video, 100, "", true, 256, font::SIZE_SMALL),
|
||||
image_restorer_(nullptr),
|
||||
image_rect_(null_rect),
|
||||
available_level_types_(),
|
||||
engine_(video, state)
|
||||
{
|
||||
filter_num_players_slider_.set_min(1);
|
||||
filter_num_players_slider_.set_max(9);
|
||||
filter_num_players_slider_.set_increment(1);
|
||||
|
||||
DBG_MP << "constructing multiplayer create dialog" << std::endl;
|
||||
|
||||
levels_menu_.set_numeric_keypress_selection(false);
|
||||
|
||||
typedef std::pair<ng::level::TYPE, std::string> level_type_info;
|
||||
std::vector<level_type_info> all_level_types;
|
||||
all_level_types.push_back(std::make_pair(ng::level::TYPE::SCENARIO, _("Scenarios")));
|
||||
all_level_types.push_back(std::make_pair(ng::level::TYPE::CAMPAIGN, _("Campaigns")));
|
||||
all_level_types.push_back(std::make_pair(ng::level::TYPE::USER_MAP, _("User Maps")));
|
||||
all_level_types.push_back(std::make_pair(ng::level::TYPE::USER_SCENARIO, _("User Scenarios")));
|
||||
all_level_types.push_back(std::make_pair(ng::level::TYPE::RANDOM_MAP, _("Random Maps")));
|
||||
|
||||
if (game_config::debug) {
|
||||
all_level_types.push_back(std::make_pair(ng::level::TYPE::SP_CAMPAIGN,
|
||||
"SP Campaigns"));
|
||||
}
|
||||
|
||||
std::vector<std::string> combo_level_names;
|
||||
|
||||
for (level_type_info type_info : all_level_types) {
|
||||
if (!engine_.get_levels_by_type_unfiltered(type_info.first).empty()) {
|
||||
available_level_types_.push_back(type_info.first);
|
||||
combo_level_names.push_back(type_info.second);
|
||||
}
|
||||
}
|
||||
|
||||
if (available_level_types_.empty()) {
|
||||
gui2::show_transient_message(video, "", _("No games found."));
|
||||
throw game::error(_("No games found."));
|
||||
}
|
||||
|
||||
level_type_combo_.set_items(combo_level_names);
|
||||
|
||||
size_t combo_new_selection = 0;
|
||||
size_t level_new_selection = 0;
|
||||
|
||||
// Set level selection according to the preferences, if possible.
|
||||
size_t type_index = 0;
|
||||
for (ng::level::TYPE type : available_level_types_) {
|
||||
if (preferences::level_type() == type.cast<int>()) {
|
||||
break;
|
||||
}
|
||||
type_index++;
|
||||
}
|
||||
if (type_index < available_level_types_.size()) {
|
||||
combo_new_selection = type_index;
|
||||
|
||||
int level_index = engine_.find_level_by_id(preferences::level());
|
||||
if (level_index != -1) {
|
||||
level_new_selection = level_index;
|
||||
}
|
||||
}
|
||||
|
||||
level_type_combo_.set_selected(combo_new_selection);
|
||||
init_level_type_changed(level_new_selection);
|
||||
|
||||
const std::vector<std::string>& era_names =
|
||||
engine_.extras_menu_item_names(ng::create_engine::ERA);
|
||||
if(era_names.empty()) {
|
||||
gui2::show_transient_message(video, "", _("No eras found."));
|
||||
throw config::error(_("No eras found"));
|
||||
}
|
||||
eras_menu_.set_items(era_names);
|
||||
|
||||
// Set era selection according to the preferences, if possible.
|
||||
int era_new_selection = engine_.find_extra_by_id(ng::create_engine::ERA,
|
||||
preferences::era());
|
||||
eras_menu_.move_selection((era_new_selection != -1) ? era_new_selection : 0);
|
||||
|
||||
std::vector<std::string> mods = engine_.extras_menu_item_names(ng::create_engine::MOD);
|
||||
mods_menu_.set_items(mods);
|
||||
mods_menu_.move_selection(0);
|
||||
// don't set 0 explicitly, because move_selection(0) may fail if there's
|
||||
// no modifications at all
|
||||
mod_selection_ = mods_menu_.selection();
|
||||
|
||||
if (mod_selection_ == -1) {
|
||||
mod_label_.set_text(_("Modifications:\nNone found."));
|
||||
}
|
||||
|
||||
gamelist_updated();
|
||||
|
||||
plugins_context_.reset(new plugins_context("Multiplayer Create"));
|
||||
|
||||
//These structure initializers create a lobby::process_data_event
|
||||
plugins_context_->set_callback("create", std::bind(&create::plugin_event_helper, this, process_event_data (true, false, false)));
|
||||
plugins_context_->set_callback("load", std::bind(&create::plugin_event_helper, this, process_event_data (false, true, false)));
|
||||
plugins_context_->set_callback("quit", std::bind(&create::plugin_event_helper, this, process_event_data (false, false, true)));
|
||||
plugins_context_->set_callback("chat", [this](const config& cfg) { send_chat_message(cfg["message"], false); }, true);
|
||||
plugins_context_->set_callback("select_level", [this](const config& cfg) { levels_menu_.move_selection(cfg["index"].to_int()); }, true);
|
||||
plugins_context_->set_callback("select_type", [this](const config& cfg) { select_level_type_helper(cfg["type"]); }, true);
|
||||
|
||||
plugins_context_->set_accessor("game_config", std::bind(&create::game_config, this));
|
||||
plugins_context_->set_accessor("get_selected", std::bind(&get_selected_helper, &engine_));
|
||||
plugins_context_->set_accessor("find_level", std::bind(&find_helper, &engine_, _1));
|
||||
}
|
||||
|
||||
void create::select_level_type_helper(const std::string & str)
|
||||
{
|
||||
for (size_t idx = 0; idx < available_level_types_.size(); idx++) {
|
||||
if (available_level_types_[idx].to_string() == str) {
|
||||
level_type_combo_.set_selected(idx);
|
||||
init_level_type_changed(0);
|
||||
process_event_impl(process_event_data(false, false, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create::~create()
|
||||
{
|
||||
try {
|
||||
// Only save the settings if the dialog was 'accepted'
|
||||
if(get_result() != CREATE) {
|
||||
DBG_MP << "destructing multiplayer create dialog - aborted game creation" << std::endl;
|
||||
return;
|
||||
}
|
||||
DBG_MP << "destructing multiplayer create dialog - a game will be created" << std::endl;
|
||||
|
||||
// Save values for next game
|
||||
DBG_MP << "storing parameter values in preferences" << std::endl;
|
||||
preferences::set_era(engine_.current_extra(ng::create_engine::ERA).id);
|
||||
preferences::set_level(engine_.current_level().id());
|
||||
preferences::set_level_type(engine_.current_level_type().cast<int>());
|
||||
preferences::set_modifications(engine_.active_mods());
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
const mp_game_settings& create::get_parameters()
|
||||
{
|
||||
return engine_.get_parameters();
|
||||
}
|
||||
|
||||
bool create::plugin_event_helper(const process_event_data & data)
|
||||
{
|
||||
process_event_impl(data);
|
||||
return get_result() == mp::ui::CONTINUE;
|
||||
}
|
||||
|
||||
void create::process_event()
|
||||
{
|
||||
int mousex, mousey;
|
||||
SDL_GetMouseState(&mousex,&mousey);
|
||||
tooltips::process(mousex, mousey);
|
||||
|
||||
process_event_data data;
|
||||
data.quit = cancel_game_.pressed();
|
||||
data.create = launch_game_.pressed() || levels_menu_.double_clicked();
|
||||
data.load = load_game_.pressed();
|
||||
|
||||
process_event_impl(data);
|
||||
}
|
||||
|
||||
void create::process_event_impl(const process_event_data & data)
|
||||
{
|
||||
if (data.quit) {
|
||||
set_result(QUIT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.create) {
|
||||
if (engine_.current_level().can_launch_game()) {
|
||||
|
||||
engine_.prepare_for_era_and_mods();
|
||||
|
||||
if (engine_.current_level_type() == ng::level::TYPE::CAMPAIGN ||
|
||||
engine_.current_level_type() == ng::level::TYPE::SP_CAMPAIGN) {
|
||||
|
||||
std::string difficulty = engine_.select_campaign_difficulty();
|
||||
if (difficulty == "CANCEL") {
|
||||
return;
|
||||
}
|
||||
|
||||
engine_.prepare_for_campaign(difficulty);
|
||||
}
|
||||
else if (engine_.current_level_type() == ng::level::TYPE::SCENARIO)
|
||||
{
|
||||
engine_.prepare_for_scenario();
|
||||
}
|
||||
else
|
||||
{
|
||||
//This means define= doesn't work for random generated scenarios
|
||||
engine_.prepare_for_other();
|
||||
}
|
||||
|
||||
engine_.prepare_for_new_level();
|
||||
|
||||
set_result(CREATE);
|
||||
return;
|
||||
} else {
|
||||
gui2::show_transient_message(video(), "",
|
||||
_("The level is invalid."));
|
||||
}
|
||||
}
|
||||
|
||||
if (level_type_combo_.changed()) {
|
||||
init_level_type_changed(0);
|
||||
}
|
||||
|
||||
if (data.load) {
|
||||
try
|
||||
{
|
||||
savegame::loadgame load(video(),
|
||||
game_config_manager::get()->game_config(), engine_.get_state());
|
||||
if (data.filename) {
|
||||
load.data().filename = *data.filename;
|
||||
if (!load.load_game()) {
|
||||
return ;
|
||||
}
|
||||
} else {
|
||||
if (!load.load_multiplayer_game()) {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
if (load.data().cancel_orders)
|
||||
engine_.get_state().cancel_orders();
|
||||
|
||||
engine_.prepare_for_saved_game();
|
||||
set_result(LOAD_GAME);
|
||||
|
||||
return;
|
||||
}
|
||||
catch(config::error&) {
|
||||
}
|
||||
}
|
||||
|
||||
if (mod_selection_ != mods_menu_.selection()) {
|
||||
mod_selection_ = mods_menu_.selection();
|
||||
engine_.set_current_mod_index(mod_selection_);
|
||||
set_description(engine_.current_extra(ng::create_engine::MOD).description);
|
||||
}
|
||||
|
||||
int changed_mod = mods_menu_.last_changed();
|
||||
if (changed_mod != -1) {
|
||||
engine_.set_current_mod_index(changed_mod);
|
||||
engine_.toggle_current_mod();
|
||||
synchronize_selections();
|
||||
}
|
||||
|
||||
bool era_changed = era_selection_ != eras_menu_.selection();
|
||||
era_selection_ = eras_menu_.selection();
|
||||
|
||||
if (era_changed) {
|
||||
engine_.set_current_era_index(era_selection_);
|
||||
|
||||
set_description(engine_.current_extra(ng::create_engine::ERA).description);
|
||||
synchronize_selections();
|
||||
}
|
||||
|
||||
if (filter_name_.text() != engine_.level_name_filter()) {
|
||||
engine_.apply_level_filter(filter_name_.text());
|
||||
init_level_type_changed(0);
|
||||
}
|
||||
|
||||
bool level_changed = level_selection_ != levels_menu_.selection();
|
||||
level_selection_ = levels_menu_.selection();
|
||||
|
||||
if (level_changed && level_selection_ >= 0) {
|
||||
init_level_changed(level_selection_);
|
||||
|
||||
synchronize_selections();
|
||||
}
|
||||
|
||||
if (engine_.generator_assigned() && generator_settings_.pressed()) {
|
||||
engine_.generator_user_config();
|
||||
|
||||
level_changed = true;
|
||||
}
|
||||
|
||||
if(engine_.generator_assigned() &&
|
||||
(level_changed || regenerate_map_.pressed())) {
|
||||
const cursor::setter cursor_setter(cursor::WAIT);
|
||||
cursor::setter cur(cursor::WAIT);
|
||||
|
||||
engine_.init_generated_level_data();
|
||||
|
||||
if (!engine_.current_level().data()["error_message"].empty())
|
||||
gui2::show_message(video(), "map generation error",
|
||||
engine_.current_level().data()["error_message"]);
|
||||
|
||||
level_changed = true;
|
||||
}
|
||||
|
||||
if(level_changed) {
|
||||
std::stringstream players;
|
||||
std::stringstream map_size;
|
||||
|
||||
players << _("Players: ");
|
||||
|
||||
engine_.current_level().set_metadata();
|
||||
|
||||
draw_level_image();
|
||||
|
||||
set_description(engine_.current_level().description());
|
||||
|
||||
switch (engine_.current_level_type().v) {
|
||||
case ng::level::TYPE::SCENARIO:
|
||||
case ng::level::TYPE::USER_MAP:
|
||||
case ng::level::TYPE::USER_SCENARIO:
|
||||
case ng::level::TYPE::RANDOM_MAP: {
|
||||
|
||||
ng::scenario* current_scenario =
|
||||
dynamic_cast<ng::scenario*>(&engine_.current_level());
|
||||
|
||||
assert(current_scenario);
|
||||
|
||||
players << current_scenario->num_players();
|
||||
map_size << _("Size: ") << current_scenario->map_size();
|
||||
|
||||
break;
|
||||
}
|
||||
case ng::level::TYPE::CAMPAIGN:
|
||||
case ng::level::TYPE::SP_CAMPAIGN: {
|
||||
ng::campaign* current_campaign =
|
||||
dynamic_cast<ng::campaign*>(&engine_.current_level());
|
||||
|
||||
assert(current_campaign);
|
||||
|
||||
players << current_campaign->min_players();
|
||||
if (current_campaign->max_players() !=
|
||||
current_campaign->min_players()) {
|
||||
|
||||
players << " to " << current_campaign->max_players();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} // end switch
|
||||
|
||||
map_size_label_.set_text(map_size.str());
|
||||
num_players_label_.set_text(players.str());
|
||||
|
||||
launch_game_.enable(engine_.current_level().can_launch_game());
|
||||
generator_settings_.enable(engine_.generator_assigned());
|
||||
regenerate_map_.enable(engine_.generator_assigned());
|
||||
}
|
||||
|
||||
if (filter_num_players_slider_.value() != engine_.player_num_filter()) {
|
||||
const int val = filter_num_players_slider_.value();
|
||||
engine_.apply_level_filter(val);
|
||||
std::stringstream ss;
|
||||
if (val == 1) {
|
||||
ss << _("Number of players: any");
|
||||
} else {
|
||||
ss << _("Number of players: ") << val;
|
||||
}
|
||||
filter_num_players_label_.set_text(ss.str());
|
||||
init_level_type_changed(0);
|
||||
}
|
||||
}
|
||||
|
||||
void create::init_level_type_changed(size_t index)
|
||||
{
|
||||
int selected = level_type_combo_.selected();
|
||||
if (selected < 0) {
|
||||
selected = 0;
|
||||
}
|
||||
|
||||
engine_.set_current_level_type(available_level_types_[selected]);
|
||||
const std::vector<std::string>& menu_item_names =
|
||||
engine_.levels_menu_item_names();
|
||||
|
||||
init_level_changed((index < menu_item_names.size()) ? index : 0);
|
||||
|
||||
levels_menu_.set_items(menu_item_names);
|
||||
levels_menu_.move_selection(index);
|
||||
|
||||
level_selection_ = -1;
|
||||
}
|
||||
|
||||
void create::init_level_changed(size_t index)
|
||||
{
|
||||
engine_.set_current_level(index);
|
||||
|
||||
// N.B. the order of hide() calls here is important
|
||||
// to avoid redrawing glitches.
|
||||
if (engine_.current_level().allow_era_choice()) {
|
||||
no_era_label_.hide(true);
|
||||
eras_menu_.hide(false);
|
||||
} else {
|
||||
eras_menu_.hide(true);
|
||||
no_era_label_.hide(false);
|
||||
}
|
||||
}
|
||||
|
||||
void create::synchronize_selections()
|
||||
{
|
||||
DBG_MP << "Synchronizing with the dependency manager" << std::endl;
|
||||
if (era_selection_ != engine_.dependency_manager().get_era_index()) {
|
||||
eras_menu_.move_selection(engine_.dependency_manager().get_era_index());
|
||||
process_event();
|
||||
}
|
||||
|
||||
if (engine_.current_level_type() != ng::level::TYPE::CAMPAIGN &&
|
||||
engine_.current_level_type() != ng::level::TYPE::SP_CAMPAIGN) {
|
||||
if (engine_.current_level().id() !=
|
||||
engine_.dependency_manager().get_scenario()) {
|
||||
|
||||
// Match scenario and scenario type
|
||||
ng::level::TYPE level_type_at_index;
|
||||
int index = engine_.find_level_by_id(
|
||||
engine_.dependency_manager().get_scenario());
|
||||
size_t type_index;
|
||||
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
level_type_at_index = engine_.find_level_type_by_id(
|
||||
engine_.dependency_manager().get_scenario());
|
||||
engine_.set_current_level_type(level_type_at_index);
|
||||
|
||||
init_level_changed(index);
|
||||
levels_menu_.set_items(engine_.levels_menu_item_names());
|
||||
levels_menu_.move_selection(index);
|
||||
type_index = 0;
|
||||
for (ng::level::TYPE type : available_level_types_) {
|
||||
if (level_type_at_index == type) {
|
||||
level_type_combo_.set_selected(type_index);
|
||||
break;
|
||||
}
|
||||
type_index++;
|
||||
}
|
||||
}
|
||||
|
||||
process_event();
|
||||
}
|
||||
|
||||
engine_.init_active_mods();
|
||||
update_mod_menu();
|
||||
}
|
||||
|
||||
void create::draw_level_image()
|
||||
{
|
||||
surface image(
|
||||
engine_.current_level().create_image_surface(image_rect_));
|
||||
|
||||
if (!image.null()) {
|
||||
SDL_Color back_color = {0,0,0,SDL_ALPHA_OPAQUE};
|
||||
draw_centered_on_background(image, image_rect_, back_color,
|
||||
video().getSurface());
|
||||
} else {
|
||||
surface& display(video().getSurface());
|
||||
sdl::fill_rect(display, &image_rect_,
|
||||
SDL_MapRGB(display->format, 0, 0, 0));
|
||||
update_rect(image_rect_);
|
||||
}
|
||||
}
|
||||
|
||||
void create::set_description(const std::string& description)
|
||||
{
|
||||
description_.set_text(description.empty() ? _("No description available.") :
|
||||
description);
|
||||
}
|
||||
|
||||
void create::update_mod_menu()
|
||||
{
|
||||
for (size_t i = 0; i<mods_menu_.number_of_items(); i++) {
|
||||
mods_menu_.set_active(i, engine_.dependency_manager().is_modification_active(i));
|
||||
}
|
||||
}
|
||||
|
||||
void create::hide_children(bool hide)
|
||||
{
|
||||
DBG_MP << (hide ? "hiding" : "showing" ) << " children widgets" << std::endl;
|
||||
|
||||
ui::hide_children(hide);
|
||||
|
||||
eras_menu_.hide(hide || !engine_.current_level().allow_era_choice());
|
||||
no_era_label_.hide(hide || engine_.current_level().allow_era_choice());
|
||||
levels_menu_.hide(hide);
|
||||
mods_menu_.hide(hide);
|
||||
|
||||
filter_name_.hide(hide);
|
||||
filter_num_players_label_.hide(hide);
|
||||
map_generator_label_.hide(hide);
|
||||
map_size_label_.hide(hide);
|
||||
era_label_.hide(hide);
|
||||
mod_label_.hide(hide);
|
||||
num_players_label_.hide(hide);
|
||||
level_type_label_.hide(hide);
|
||||
|
||||
level_type_combo_.hide(hide);
|
||||
|
||||
cancel_game_.hide(hide);
|
||||
launch_game_.hide(hide);
|
||||
|
||||
load_game_.hide(hide);
|
||||
|
||||
regenerate_map_.hide(hide);
|
||||
generator_settings_.hide(hide);
|
||||
|
||||
filter_num_players_slider_.hide(hide);
|
||||
|
||||
description_.hide(hide);
|
||||
filter_name_.hide(hide);
|
||||
|
||||
if (hide) {
|
||||
image_restorer_.reset(nullptr);
|
||||
} else {
|
||||
image_restorer_.reset(new surface_restorer(&video(), image_rect_));
|
||||
|
||||
engine_.current_level().set_metadata();
|
||||
draw_level_image();
|
||||
}
|
||||
}
|
||||
|
||||
void create::layout_children(const SDL_Rect& rect)
|
||||
{
|
||||
DBG_MP << "laying out the children" << std::endl;
|
||||
|
||||
ui::layout_children(rect);
|
||||
|
||||
const int border_size = 6;
|
||||
const int column_border_size = 10;
|
||||
|
||||
SDL_Rect ca = client_area();
|
||||
int xpos = ca.x;
|
||||
int ypos = ca.y;
|
||||
|
||||
// 222 is two times a button's minimal width plus one time border_size.
|
||||
// Instead of binding this value to the actual button widths, I chose this
|
||||
// because it makes no difference for most languages, and where it does, I
|
||||
// guess we'd prefer having the buttons less neatly aligned to having a
|
||||
// potentially giant image.
|
||||
const int image_width = ca.h < 500 ? 111 : 222;
|
||||
const int menu_width = (ca.w - 3 * column_border_size - image_width) / 3;
|
||||
const int eras_menu_height = (ca.h / 2 - era_label_.height() -
|
||||
2 * border_size - cancel_game_.height());
|
||||
const int mods_menu_height = (ca.h / 2 - mod_label_.height() -
|
||||
3 * border_size - cancel_game_.height());
|
||||
|
||||
// Dialog title
|
||||
ypos += title().height() + border_size;
|
||||
|
||||
// Save ypos here (column top)
|
||||
int ypos_columntop = ypos;
|
||||
|
||||
// First column: image & random map options
|
||||
image_rect_ = sdl::create_rect(xpos, ypos, image_width, image_width);
|
||||
ypos += image_width + border_size;
|
||||
|
||||
num_players_label_.set_location(xpos, ypos);
|
||||
ypos += num_players_label_.height() + border_size;
|
||||
|
||||
map_size_label_.set_location(xpos, ypos);
|
||||
ypos += map_size_label_.height() + 2 * border_size;
|
||||
|
||||
const int ypos1 = ypos;
|
||||
const int xpos1 = xpos;
|
||||
// The description box is set later
|
||||
|
||||
// Second column: filtering options
|
||||
ypos = ypos_columntop;
|
||||
xpos += image_width + column_border_size;
|
||||
filter_name_label_.set_location(xpos, ypos);
|
||||
filter_name_.set_location(xpos + filter_name_label_.width() + border_size, ypos);
|
||||
filter_name_.set_measurements(menu_width - border_size - filter_name_label_.width(), filter_name_label_.height());
|
||||
ypos += filter_name_.height() + border_size;
|
||||
filter_num_players_label_.set_location(xpos, ypos);
|
||||
ypos += filter_num_players_label_.height() + border_size;
|
||||
filter_num_players_slider_.set_location(xpos, ypos);
|
||||
filter_num_players_slider_.set_width(menu_width);
|
||||
ypos += filter_num_players_slider_.height() + border_size;
|
||||
map_generator_label_.set_location(xpos, ypos);
|
||||
ypos += map_generator_label_.height() + border_size;
|
||||
regenerate_map_.set_location(xpos, ypos);
|
||||
ypos += regenerate_map_.height() + border_size;
|
||||
generator_settings_.set_location(xpos, ypos);
|
||||
ypos += generator_settings_.height() + border_size;
|
||||
load_game_.set_location(xpos, ypos + 4 * border_size);
|
||||
|
||||
// And now the description box
|
||||
description_.set_location(xpos1, std::max(ypos,ypos1));
|
||||
description_.set_measurements(image_width + border_size + menu_width, ca.h + ca.y - std::max(ypos,ypos1) - border_size);
|
||||
description_.set_wrap(true);
|
||||
ypos += description_.height() + border_size;
|
||||
|
||||
//Third column: levels menu
|
||||
ypos = ypos_columntop;
|
||||
xpos += menu_width + column_border_size;
|
||||
level_type_label_.set_location(xpos, ypos);
|
||||
ypos += level_type_label_.height() + border_size;
|
||||
level_type_combo_.set_location(xpos, ypos);
|
||||
ypos += level_type_combo_.height() + border_size;
|
||||
|
||||
const int levels_menu_y_offset = (ca.w < 900 || ca.h < 500) ?
|
||||
((cancel_game_.height() + border_size) * -1) : 0;
|
||||
levels_menu_.set_max_width(menu_width);
|
||||
levels_menu_.set_max_height(ca.h + ca.y - ypos + levels_menu_y_offset);
|
||||
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(engine_.levels_menu_item_names());
|
||||
levels_menu_.move_selection(levelsel);
|
||||
|
||||
// Place game type combo and label in the middle of levels menu
|
||||
// by x axis.
|
||||
const int level_type_combo_x_offset = (levels_menu_.width() -
|
||||
level_type_combo_.width()) / 2;
|
||||
level_type_combo_.set_location(
|
||||
level_type_combo_.location().x + level_type_combo_x_offset,
|
||||
level_type_combo_.location().y);
|
||||
const int level_type_label_x_offset = (levels_menu_.width() -
|
||||
level_type_label_.width()) / 2;
|
||||
level_type_label_.set_location(
|
||||
level_type_label_.location().x + level_type_label_x_offset,
|
||||
level_type_label_.location().y);
|
||||
|
||||
//Fourth column: eras & mods menu
|
||||
ypos = ypos_columntop;
|
||||
xpos += menu_width + column_border_size;
|
||||
era_label_.set_location(xpos, ypos);
|
||||
ypos += era_label_.height() + border_size;
|
||||
no_era_label_.set_location(xpos, ypos);
|
||||
eras_menu_.set_max_width(menu_width);
|
||||
eras_menu_.set_max_height(eras_menu_height);
|
||||
eras_menu_.set_location(xpos, ypos);
|
||||
// Menu dimensions are only updated when items are set. So do this now.
|
||||
int erasel_save = eras_menu_.selection();
|
||||
eras_menu_.set_items(engine_.extras_menu_item_names(ng::create_engine::ERA));
|
||||
eras_menu_.move_selection(erasel_save);
|
||||
ypos += eras_menu_height;
|
||||
|
||||
//TODO: use when mods_menu_ would be functional.
|
||||
mod_label_.set_location(xpos, ypos);
|
||||
ypos += mod_label_.height() + border_size;
|
||||
mods_menu_.set_max_width(menu_width);
|
||||
mods_menu_.set_max_height(mods_menu_height);
|
||||
mods_menu_.set_location(xpos, ypos);
|
||||
if (mods_menu_.number_of_items() > 0) {
|
||||
ypos += mods_menu_.height() + border_size;
|
||||
}
|
||||
|
||||
// Make eras and mods menus the same width for alignment
|
||||
eras_menu_.set_width(std::max(mods_menu_.width(),eras_menu_.width()));
|
||||
mods_menu_.set_width(std::max(mods_menu_.width(),eras_menu_.width()));
|
||||
|
||||
// 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.x + ca.w - right_button->width(),
|
||||
ca.y + ca.h - right_button->height());
|
||||
left_button->set_location(right_button->location().x - left_button->width() -
|
||||
gui::ButtonHPadding, ca.y + ca.h - left_button->height());
|
||||
|
||||
if (ca.h < 500) {
|
||||
load_game_.set_location(left_button->location().x - load_game_.width() -
|
||||
gui::ButtonHPadding, ca.y + ca.h - load_game_.height());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mp
|
||||
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 - 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 */
|
||||
|
||||
#ifndef MULTIPLAYER_CREATE_HPP_INCLUDED
|
||||
#define MULTIPLAYER_CREATE_HPP_INCLUDED
|
||||
|
||||
#include "depcheck.hpp"
|
||||
#include "create_engine.hpp"
|
||||
#include "multiplayer_ui.hpp"
|
||||
#include "widgets/slider.hpp"
|
||||
#include "widgets/combo.hpp"
|
||||
#include "widgets/multimenu.hpp"
|
||||
#include "tooltips.hpp"
|
||||
|
||||
namespace mp {
|
||||
|
||||
class create : public mp::ui
|
||||
{
|
||||
public:
|
||||
create(CVideo& v, wesnothd_connection* connection, const config& game_config, saved_game& state,
|
||||
chat& c, config& gamelist);
|
||||
~create();
|
||||
|
||||
const mp_game_settings& get_parameters();
|
||||
|
||||
protected:
|
||||
virtual void layout_children(const SDL_Rect& rect);
|
||||
virtual void process_event();
|
||||
virtual void hide_children(bool hide=true);
|
||||
|
||||
private:
|
||||
void init_level_type_changed(size_t index);
|
||||
void init_level_changed(size_t index);
|
||||
|
||||
void synchronize_selections();
|
||||
|
||||
void draw_level_image();
|
||||
|
||||
void set_description(const std::string& description);
|
||||
|
||||
void update_mod_menu();
|
||||
|
||||
std::string select_campaign_difficulty();
|
||||
|
||||
tooltips::manager tooltip_manager_;
|
||||
int era_selection_;
|
||||
int mod_selection_;
|
||||
int level_selection_;
|
||||
|
||||
gui::menu eras_menu_;
|
||||
gui::menu levels_menu_;
|
||||
gui::multimenu mods_menu_;
|
||||
|
||||
gui::label filter_name_label_;
|
||||
gui::label filter_num_players_label_;
|
||||
gui::label map_generator_label_;
|
||||
gui::label era_label_;
|
||||
gui::label no_era_label_;
|
||||
gui::label mod_label_;
|
||||
gui::label map_size_label_;
|
||||
gui::label num_players_label_;
|
||||
gui::label level_type_label_;
|
||||
|
||||
gui::button launch_game_;
|
||||
gui::button cancel_game_;
|
||||
gui::button regenerate_map_;
|
||||
gui::button generator_settings_;
|
||||
gui::button load_game_;
|
||||
|
||||
gui::combo level_type_combo_;
|
||||
|
||||
gui::slider filter_num_players_slider_;
|
||||
|
||||
gui::textbox description_;
|
||||
gui::textbox filter_name_;
|
||||
|
||||
std::unique_ptr<surface_restorer> image_restorer_;
|
||||
SDL_Rect image_rect_;
|
||||
|
||||
std::vector<ng::level::TYPE> available_level_types_;
|
||||
|
||||
ng::create_engine engine_;
|
||||
|
||||
struct process_event_data {
|
||||
bool create, load, quit;
|
||||
boost::optional<std::string> filename;
|
||||
|
||||
process_event_data()
|
||||
: create(false), load(false), quit(false), filename()
|
||||
{}
|
||||
process_event_data(bool c, bool l, bool q)
|
||||
: create(c), load(l), quit(q), filename()
|
||||
{}
|
||||
process_event_data(const std::string & fname)
|
||||
: create(false), load(true), quit(false), filename(fname)
|
||||
{}
|
||||
};
|
||||
|
||||
void process_event_impl(const process_event_data &);
|
||||
bool plugin_event_helper(const process_event_data &);
|
||||
|
||||
void select_level_type_helper(const std::string & str);
|
||||
};
|
||||
|
||||
} // end namespace mp
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,267 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 - 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 multiplayer_lobby.hpp */
|
||||
|
||||
#ifndef MULTIPLAYER_LOBBY_HPP_INCLUDED
|
||||
#define MULTIPLAYER_LOBBY_HPP_INCLUDED
|
||||
|
||||
#include "multiplayer_ui.hpp"
|
||||
#include "game_preferences.hpp"
|
||||
#include "image.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
class config;
|
||||
class video;
|
||||
class CVideo;
|
||||
|
||||
/**
|
||||
* This module controls the multiplayer lobby.
|
||||
*
|
||||
* A section on the server which allows players to chat, create games, and join
|
||||
* games.
|
||||
*/
|
||||
namespace mp {
|
||||
|
||||
enum ADDON_REQ { SATISFIED, NEED_DOWNLOAD, CANNOT_SATISFY };
|
||||
|
||||
struct required_addon {
|
||||
std::string addon_id;
|
||||
ADDON_REQ outcome;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
class gamebrowser : public gui::menu {
|
||||
public:
|
||||
struct game_item {
|
||||
|
||||
game_item() :
|
||||
mini_map(),
|
||||
id(),
|
||||
map_data(),
|
||||
name(),
|
||||
map_info(),
|
||||
map_info_size(),
|
||||
era_and_mod_info(),
|
||||
gold(),
|
||||
xp(),
|
||||
vision(),
|
||||
status(),
|
||||
time_limit(),
|
||||
vacant_slots(0),
|
||||
current_turn(0),
|
||||
reloaded(false),
|
||||
started(false),
|
||||
fog(false),
|
||||
shroud(false),
|
||||
observers(false),
|
||||
shuffle_sides(false),
|
||||
use_map_settings(false),
|
||||
verified(false),
|
||||
password_required(false),
|
||||
have_scenario(false),
|
||||
have_era(false),
|
||||
have_all_mods(false),
|
||||
addons(),
|
||||
addons_outcome(SATISFIED)
|
||||
{
|
||||
}
|
||||
|
||||
surface mini_map;
|
||||
std::string id;
|
||||
std::string map_data;
|
||||
std::string name;
|
||||
std::string map_info;
|
||||
std::string map_info_size;
|
||||
std::string era_and_mod_info;
|
||||
std::string gold;
|
||||
std::string xp;
|
||||
std::string vision;
|
||||
std::string status;
|
||||
std::string time_limit;
|
||||
size_t vacant_slots;
|
||||
unsigned int current_turn;
|
||||
bool reloaded;
|
||||
bool started;
|
||||
bool fog;
|
||||
bool shroud;
|
||||
bool observers;
|
||||
bool registered_users_only;
|
||||
bool shuffle_sides;
|
||||
bool use_map_settings;
|
||||
bool verified;
|
||||
bool password_required;
|
||||
bool have_scenario;
|
||||
bool have_era;
|
||||
bool have_all_mods;
|
||||
std::vector<required_addon> addons;
|
||||
ADDON_REQ addons_outcome;
|
||||
};
|
||||
gamebrowser(CVideo& video, const config &map_hashes);
|
||||
void scroll(unsigned int pos);
|
||||
void handle_event(const SDL_Event& event);
|
||||
void set_inner_location(const SDL_Rect& rect);
|
||||
void set_item_height(unsigned int height);
|
||||
|
||||
void populate_game_item(game_item &, const config &, const config &, const std::vector<std::string> &);
|
||||
void populate_game_item_campaign_or_scenario_info(game_item &, const config &, const config &, bool &);
|
||||
void populate_game_item_map_info(game_item &, const config &, const config &, bool &);
|
||||
void populate_game_item_era_info(game_item &, const config &, const config &, bool &);
|
||||
void populate_game_item_mod_info(game_item &, const config &, const config &, bool &);
|
||||
void populate_game_item_addons_installed(game_item &, const config &, const std::vector<std::string> &);
|
||||
|
||||
void set_game_items(const config& cfg, const config& game_config, const std::vector<std::string> & installed_addons);
|
||||
void draw();
|
||||
void draw_contents();
|
||||
void draw_row(const size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
|
||||
SDL_Rect get_item_rect(size_t index) const;
|
||||
bool empty() const { return games_.empty(); }
|
||||
bool selection_is_joinable() const
|
||||
{ return selection_in_joinable_state() && (!selection_needs_content() || selection_needs_addons()); }
|
||||
bool selection_is_observable() const
|
||||
{ return selection_in_observable_state() && (!selection_needs_content() || selection_needs_addons()); }
|
||||
bool selection_needs_content() const
|
||||
{ return empty() ? false : !games_[selected_].have_era ||
|
||||
!games_[selected_].have_all_mods ||
|
||||
!games_[selected_].have_scenario; }
|
||||
bool selection_needs_addons() const
|
||||
{ return empty() ? false : (games_[selected_].addons_outcome != SATISFIED); }
|
||||
bool selection_in_joinable_state() const
|
||||
{ return empty() ? false : (games_[selected_].vacant_slots > 0 && !games_[selected_].started); }
|
||||
// Moderators may observe any game.
|
||||
bool selection_in_observable_state() const
|
||||
{ return empty() ? false : (games_[selected_].observers || preferences::is_authenticated()); }
|
||||
|
||||
ADDON_REQ selection_addon_outcome() const
|
||||
{ return empty() ? SATISFIED : games_[selected_].addons_outcome; }
|
||||
const std::vector<required_addon> * selection_addon_requirements() const
|
||||
{ return empty() ? nullptr : &games_[selected_].addons; }
|
||||
bool selected() const { return double_clicked_ && !empty(); }
|
||||
void reset_selection() { double_clicked_ = false; }
|
||||
int selection() const { return selected_; }
|
||||
game_item selected_game() { return games_[selected_]; }
|
||||
void select_game(const std::string& id);
|
||||
bool game_matches_filter(const game_item& i, const config& cfg);
|
||||
|
||||
protected:
|
||||
unsigned int row_height() const { return item_height_ + (2 * style_->get_thickness()); }
|
||||
private:
|
||||
image::locator gold_icon_locator_;
|
||||
image::locator xp_icon_locator_;
|
||||
image::locator map_size_icon_locator_;
|
||||
image::locator vision_icon_locator_;
|
||||
image::locator time_limit_icon_locator_;
|
||||
image::locator observer_icon_locator_;
|
||||
image::locator no_observer_icon_locator_;
|
||||
image::locator shuffle_sides_icon_locator_;
|
||||
|
||||
const config &map_hashes_;
|
||||
|
||||
unsigned int item_height_;
|
||||
int margin_;
|
||||
int minimap_size_;
|
||||
int h_padding_;
|
||||
int h_padding_image_to_text_;
|
||||
int header_height_;
|
||||
size_t selected_;
|
||||
std::pair<size_t, size_t> visible_range_;
|
||||
std::vector<game_item> games_;
|
||||
std::vector<size_t> redraw_items_;
|
||||
std::vector<int> widths_;
|
||||
bool double_clicked_;
|
||||
bool ignore_next_doubleclick_;
|
||||
bool last_was_doubleclick_;
|
||||
};
|
||||
|
||||
class lobby : public ui
|
||||
{
|
||||
public:
|
||||
lobby(CVideo& v, wesnothd_connection* connection, const config& cfg, chat& c, config& gamelist, const std::vector<std::string> & installed_addons);
|
||||
|
||||
virtual void process_event();
|
||||
|
||||
int current_turn;
|
||||
protected:
|
||||
virtual void hide_children(bool hide=true);
|
||||
virtual void layout_children(const SDL_Rect& rect);
|
||||
virtual void process_network_data(const config& data);
|
||||
|
||||
virtual void gamelist_updated(bool silent=true);
|
||||
private:
|
||||
|
||||
class lobby_sorter : public gui::menu::basic_sorter
|
||||
{
|
||||
const config& cfg_;
|
||||
|
||||
bool column_sortable(int column) const;
|
||||
bool less(int column, const gui::menu::item& row1, const gui::menu::item& row2) const;
|
||||
|
||||
enum { MAP_COLUMN = 0, STATUS_COLUMN = 2};
|
||||
public:
|
||||
lobby_sorter(const config& cfg);
|
||||
};
|
||||
|
||||
boost::dynamic_bitset<> game_vacant_slots_;
|
||||
boost::dynamic_bitset<> game_observers_;
|
||||
|
||||
gui::button observe_game_;
|
||||
gui::button join_game_;
|
||||
gui::button create_game_;
|
||||
gui::combo replay_options_;
|
||||
gui::button game_preferences_;
|
||||
gui::button quit_game_;
|
||||
|
||||
gui::button apply_filter_;
|
||||
gui::button invert_filter_;
|
||||
gui::button vacant_slots_;
|
||||
gui::button friends_in_game_;
|
||||
gui::label filter_label_;
|
||||
gui::textbox filter_text_;
|
||||
|
||||
int last_selected_game_;
|
||||
|
||||
lobby_sorter sorter_;
|
||||
gamebrowser games_menu_;
|
||||
|
||||
std::map<std::string,std::string> minimaps_;
|
||||
|
||||
std::string search_string_;
|
||||
|
||||
const std::vector<std::string> & installed_addons_;
|
||||
|
||||
struct process_event_data {
|
||||
bool join;
|
||||
bool observe;
|
||||
bool create;
|
||||
bool quit;
|
||||
|
||||
process_event_data()
|
||||
: join(false), observe(false), create(false), quit(false)
|
||||
{}
|
||||
|
||||
process_event_data(bool j, bool o, bool c, bool q)
|
||||
: join(j), observe(o), create(c), quit(q)
|
||||
{}
|
||||
};
|
||||
|
||||
// This is added to make it easier for plugins to trigger events, and to separate some of the "controller" from the internal logic
|
||||
void process_event_impl(const process_event_data &);
|
||||
bool plugin_event_helper(const process_event_data &);
|
||||
};
|
||||
|
||||
} // end namespace mp
|
||||
|
||||
#endif
|
|
@ -1,800 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2005 - 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.
|
||||
*/
|
||||
|
||||
#include "global.hpp"
|
||||
|
||||
#include "construct_dialog.hpp"
|
||||
#include "video.hpp"
|
||||
#include "font/sdl_ttf.hpp"
|
||||
#include "font/standard_colors.hpp"
|
||||
#include "formatter.hpp"
|
||||
#include "game_preferences.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "gui/dialogs/multiplayer/mp_cmd_wrapper.hpp"
|
||||
#include "gui/dialogs/loadscreen.hpp"
|
||||
#include "lobby_preferences.hpp"
|
||||
#include "log.hpp"
|
||||
#include "font/marked-up_text.hpp"
|
||||
#include "menu_events.hpp"
|
||||
#include "game_initialization/multiplayer.hpp"
|
||||
#include "game_initialization/multiplayer_ui.hpp"
|
||||
#include "game_initialization/multiplayer_lobby.hpp" //needed for dynamic cast when implementing the lobby_sounds preference
|
||||
#include "mp_ui_alerts.hpp"
|
||||
#include "wml_separators.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "scripting/plugins/context.hpp"
|
||||
#include "scripting/plugins/manager.hpp"
|
||||
#include "team.hpp"
|
||||
#include "sdl/utils.hpp"
|
||||
#include "sdl/rect.hpp"
|
||||
#include "wesnothd_connection.hpp"
|
||||
|
||||
static lg::log_domain log_config("config");
|
||||
#define ERR_CF LOG_STREAM(err, log_config)
|
||||
|
||||
static lg::log_domain log_network("network");
|
||||
#define LOG_NW LOG_STREAM(info, log_network)
|
||||
#define ERR_NW LOG_STREAM(err, log_network)
|
||||
|
||||
static lg::log_domain log_mp("mp/main");
|
||||
#define DBG_MP LOG_STREAM(debug, log_mp)
|
||||
|
||||
namespace {
|
||||
/** The maximum number of messages in the chat history. */
|
||||
const size_t max_messages = 256;
|
||||
|
||||
class user_menu_style : public gui::menu::imgsel_style {
|
||||
public:
|
||||
user_menu_style() : gui::menu::imgsel_style("dialogs/selection", false,
|
||||
0x000000, 0x4a4440, 0x999999,
|
||||
0.0, 0.2, 0.2),
|
||||
item_size_(sdl::empty_rect)
|
||||
{}
|
||||
virtual void init();
|
||||
virtual SDL_Rect item_size(const std::string& /*item*/) const { return item_size_; }
|
||||
void set_width(const int width) { item_size_.w = width; }
|
||||
private:
|
||||
SDL_Rect item_size_;
|
||||
};
|
||||
|
||||
void user_menu_style::init()
|
||||
{
|
||||
imgsel_style::init();
|
||||
item_size_.h = font::get_max_height(font_size_);
|
||||
scale_images(-1, item_size_.h);
|
||||
item_size_.h += 2 * thickness_;
|
||||
}
|
||||
|
||||
user_menu_style umenu_style;
|
||||
|
||||
} // anon namespace
|
||||
|
||||
namespace mp {
|
||||
|
||||
std::string get_color_string(int id)
|
||||
{
|
||||
std::string prefix = team::get_side_highlight(id);
|
||||
std::map<std::string, t_string>::iterator name = game_config::team_rgb_name.find(std::to_string(id + 1));
|
||||
if(name != game_config::team_rgb_name.end()){
|
||||
return prefix + name->second;
|
||||
}else{
|
||||
return prefix + _("Invalid Color");
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_color_string(const std::string& id)
|
||||
{
|
||||
std::map<std::string, color_range>::iterator i_color = game_config::team_rgb_range.find(id);
|
||||
std::map<std::string, t_string>::iterator i_name = game_config::team_rgb_name.find(id);
|
||||
bool has_color = i_color != game_config::team_rgb_range.end();
|
||||
bool has_name= i_name != game_config::team_rgb_name.end();
|
||||
|
||||
return rgb2highlight(has_color ? i_color->second.mid() : 0x00FF0000) + (has_name ? std::string(i_name->second) : _("Invalid Color"));
|
||||
}
|
||||
|
||||
chat::chat() :
|
||||
message_history_(),
|
||||
last_update_()
|
||||
{
|
||||
}
|
||||
|
||||
void chat::add_message(const time_t& time, const std::string& user,
|
||||
const std::string& message)
|
||||
{
|
||||
message_history_.push_back(msg(time, user, message));
|
||||
|
||||
while (message_history_.size() > max_messages) {
|
||||
message_history_.pop_front();
|
||||
|
||||
if (last_update_ > 0)
|
||||
last_update_--;
|
||||
}
|
||||
}
|
||||
|
||||
void chat::init_textbox(gui::textbox& textbox)
|
||||
{
|
||||
for(msg_hist::const_iterator itor = message_history_.begin();
|
||||
itor != message_history_.end(); ++itor) {
|
||||
textbox.append_text(format_message(*itor), true, color_message(*itor));
|
||||
}
|
||||
|
||||
last_update_ = message_history_.size();
|
||||
}
|
||||
|
||||
void chat::update_textbox(gui::textbox& textbox)
|
||||
{
|
||||
//DBG_MP << "update_textbox...\n";
|
||||
for(msg_hist::const_iterator itor = message_history_.begin() + last_update_;
|
||||
itor != message_history_.end(); ++itor) {
|
||||
textbox.append_text(format_message(*itor), true, color_message(*itor));
|
||||
}
|
||||
//DBG_MP << "update_textbox end\n";
|
||||
|
||||
last_update_ = message_history_.size();
|
||||
}
|
||||
|
||||
void chat::clear_history()
|
||||
{
|
||||
message_history_.clear();
|
||||
last_update_ = 0;
|
||||
}
|
||||
|
||||
std::string chat::format_message(const msg& message)
|
||||
{
|
||||
std::string msg_text = message.message;
|
||||
if(message.user == "server"
|
||||
|| message.user.substr(0,29) == "whisper: server message from ") {
|
||||
std::string::const_iterator after_markup =
|
||||
font::parse_markup(message.message.begin(), message.message.end(), nullptr, nullptr, nullptr);
|
||||
|
||||
msg_text = std::string(after_markup,message.message.end());
|
||||
}
|
||||
if(message.message.substr(0,3) == "/me") {
|
||||
return preferences::get_chat_timestamp(message.time) + "<" + message.user
|
||||
+ msg_text.substr(3) + ">\n";
|
||||
} else {
|
||||
return preferences::get_chat_timestamp(message.time) + "<" + message.user
|
||||
+ "> " + msg_text + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Color chat::color_message(const msg& message) {
|
||||
SDL_Color c = font::NORMAL_COLOR;
|
||||
// Normal users are not allowed to color their messages
|
||||
if(message.user == "server"
|
||||
|| message.user.substr(0,29) == "whisper: server message from ") {
|
||||
font::parse_markup(message.message.begin(), message.message.end(), nullptr, &c, nullptr);
|
||||
// Highlight private messages too
|
||||
} else if(message.user.substr(0,8) == "whisper:") {
|
||||
c = font::LABEL_COLOR;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
ui::ui(CVideo& video, wesnothd_connection* connection, const std::string& title, const config& cfg, chat& c, config& gamelist) :
|
||||
gui::widget(video),
|
||||
video_(video),
|
||||
wesnothd_connection_(connection),
|
||||
initialized_(false),
|
||||
gamelist_initialized_(false),
|
||||
|
||||
game_config_(cfg),
|
||||
chat_(c),
|
||||
gamelist_(gamelist),
|
||||
|
||||
title_(video_, title, font::SIZE_LARGE, font::TITLE_COLOR),
|
||||
entry_textbox_(video_, 100),
|
||||
chat_textbox_(video_, 100, "", false),
|
||||
users_menu_(video_, std::vector<std::string>(), false, -1, -1, nullptr, &umenu_style),
|
||||
|
||||
user_list_(),
|
||||
selected_game_(""),
|
||||
selected_user_(""),
|
||||
selected_user_changed_(false),
|
||||
|
||||
result_(CONTINUE),
|
||||
gamelist_refresh_(false),
|
||||
lobby_clock_(0),
|
||||
whisper_warnings_(),
|
||||
plugins_context_(nullptr)
|
||||
{
|
||||
const SDL_Rect area = sdl::create_rect(0
|
||||
, 0
|
||||
, video.getx()
|
||||
, video.gety());
|
||||
users_menu_.set_numeric_keypress_selection(false);
|
||||
set_location(area);
|
||||
}
|
||||
|
||||
void ui::process_network()
|
||||
{
|
||||
config data;
|
||||
if(receive_from_server(data)) {
|
||||
process_network_data(data);
|
||||
}
|
||||
|
||||
//apply diffs at a set interval
|
||||
if(gamelist_refresh_ && SDL_GetTicks() - lobby_clock_ > game_config::lobby_refresh)
|
||||
{
|
||||
const cursor::setter cursor_setter(cursor::WAIT);
|
||||
gamelist_updated(false);
|
||||
gamelist_refresh_ = false;
|
||||
lobby_clock_ = SDL_GetTicks();
|
||||
}
|
||||
}
|
||||
|
||||
ui::result ui::get_result()
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
|
||||
ui::result ui::set_result(ui::result res)
|
||||
{
|
||||
result_ = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
const int ui::xscale_base = 1024;
|
||||
const int ui::yscale_base = 768;
|
||||
|
||||
int ui::xscale(int x) const
|
||||
{
|
||||
return (x * width())/ui::xscale_base;
|
||||
}
|
||||
|
||||
int ui::yscale(int y) const
|
||||
{
|
||||
return (y * height())/ui::yscale_base;
|
||||
}
|
||||
|
||||
SDL_Rect ui::client_area() const
|
||||
{
|
||||
SDL_Rect res;
|
||||
|
||||
res.x = xscale(10) + 10;
|
||||
res.y = yscale(38) + 10;
|
||||
res.w = xscale(828) > 12 ? xscale(828) - 12 : 0;
|
||||
res.h = yscale(520) > 12 ? yscale(520) - 12 : 0;
|
||||
|
||||
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"));
|
||||
background = scale_surface(background, video().getx(), video().gety());
|
||||
if(background == nullptr)
|
||||
return;
|
||||
sdl_blit(background, nullptr, video().getSurface(), nullptr);
|
||||
hide_children(false);
|
||||
}
|
||||
|
||||
void ui::set_location(const SDL_Rect& rect)
|
||||
{
|
||||
hide_children();
|
||||
widget::set_location(rect);
|
||||
layout_children(rect);
|
||||
if(!initialized_) {
|
||||
chat_textbox_.set_wrap(true);
|
||||
chat_.init_textbox(chat_textbox_);
|
||||
chat_textbox_.set_edit_target(&entry_textbox_);
|
||||
initialized_ = true;
|
||||
}
|
||||
hide_children(false);
|
||||
}
|
||||
|
||||
void ui::process_event()
|
||||
{
|
||||
}
|
||||
|
||||
void ui::handle_event(const SDL_Event& event)
|
||||
{
|
||||
if (gui2::dialogs::loading_screen::displaying()) {
|
||||
return;
|
||||
}
|
||||
gui::widget::handle_event(event);
|
||||
|
||||
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) {
|
||||
SDL_Rect new_location;
|
||||
new_location.x = 0;
|
||||
new_location.y = 0;
|
||||
new_location.w = event.window.data1;
|
||||
new_location.h = event.window.data2;
|
||||
set_location(new_location);
|
||||
}
|
||||
|
||||
if(event.type == SDL_KEYDOWN) {
|
||||
handle_key_event(event.key);
|
||||
}
|
||||
if(users_menu_.double_clicked()) {
|
||||
std::string usr_text = user_list_[users_menu_.selection()];
|
||||
Uint32 show_time = SDL_GetTicks();
|
||||
|
||||
// Hack: for some reason the help string stays visible for ever
|
||||
/** @todo find out why the help string stays visible and fix it */
|
||||
video().clear_all_help_strings();
|
||||
|
||||
gui2::dialogs::mp_cmd_wrapper dlg(_("Selected user: ") + usr_text);
|
||||
dlg.show(video());
|
||||
|
||||
std::stringstream msg;
|
||||
switch(dlg.get_retval()) {
|
||||
case -1:
|
||||
if(!dlg.message().empty()) msg << "/msg " << usr_text << ' ' << dlg.message();
|
||||
break;
|
||||
case 1:
|
||||
msg << "/friend " << usr_text;
|
||||
break;
|
||||
case 2:
|
||||
msg << "/ignore " << usr_text;
|
||||
break;
|
||||
case 3:
|
||||
msg << "/remove " << usr_text;
|
||||
break;
|
||||
case 4:
|
||||
msg << "/query status " << usr_text;
|
||||
break;
|
||||
case 5:
|
||||
msg << "/query kick " << usr_text;
|
||||
if(!dlg.reason().empty()) msg << ' ' << dlg.reason();
|
||||
break;
|
||||
case 6:
|
||||
msg << "/query kban " << usr_text;
|
||||
if(!dlg.time().empty()) msg << ' ' << dlg.time();
|
||||
if(!dlg.reason().empty()) msg << ' ' << dlg.reason();
|
||||
}
|
||||
|
||||
chat_handler::do_speak(msg.str());
|
||||
|
||||
if(show_time + 60000 < SDL_GetTicks()) {
|
||||
//if the dialog has been open for a long time, refresh the lobby
|
||||
config request;
|
||||
request.add_child("refresh_lobby");
|
||||
send_to_server(request);
|
||||
}
|
||||
}
|
||||
if(users_menu_.selection() > 0 // -1 indicates an invalid selection
|
||||
&& selected_user_ != user_list_[users_menu_.selection()]) {
|
||||
selected_user_ = user_list_[users_menu_.selection()];
|
||||
selected_user_changed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ui::add_chat_message(const time_t& time, const std::string& speaker, int /*side*/, const std::string& message, events::chat_handler::MESSAGE_TYPE /*type*/)
|
||||
{
|
||||
chat_.add_message(time, speaker, message);
|
||||
chat_.update_textbox(chat_textbox_);
|
||||
}
|
||||
|
||||
void ui::send_chat_message(const std::string& message, bool /*allies_only*/)
|
||||
{
|
||||
config data, msg;
|
||||
msg["message"] = message;
|
||||
msg["sender"] = preferences::login();
|
||||
data.add_child("message", msg);
|
||||
|
||||
add_chat_message(time(nullptr), preferences::login(),0, message); //local echo
|
||||
send_to_server(data);
|
||||
}
|
||||
|
||||
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 || event.keysym.sym == SDLK_KP_ENTER) && !entry_textbox_.text().empty()) {
|
||||
|
||||
chat_handler::do_speak(entry_textbox_.text());
|
||||
entry_textbox_.clear();
|
||||
// nick tab-completion
|
||||
} else if(event.keysym.sym == SDLK_TAB ) {
|
||||
std::string text = entry_textbox_.text();
|
||||
std::vector<std::string> matches = user_list_;
|
||||
// Exclude own nick from tab-completion.
|
||||
matches.erase(std::remove(matches.begin(), matches.end(),
|
||||
preferences::login()), matches.end());
|
||||
const bool line_start = utils::word_completion(text, matches);
|
||||
|
||||
if (matches.empty()) return;
|
||||
|
||||
if (matches.size() == 1) {
|
||||
text.append(line_start ? ": " : " ");
|
||||
} else {
|
||||
std::string completion_list = utils::join(matches, " ");
|
||||
chat_.add_message(time(nullptr), "", completion_list);
|
||||
chat_.update_textbox(chat_textbox_);
|
||||
}
|
||||
entry_textbox_.set_text(text);
|
||||
}
|
||||
}
|
||||
|
||||
void ui::process_message(const config& msg, const bool whisper) {
|
||||
const std::string& sender = msg["sender"];
|
||||
const std::string& message = msg["message"];
|
||||
std::string room = msg["room"];
|
||||
if (!preferences::parse_should_show_lobby_join(sender, message)) return;
|
||||
if (preferences::is_ignored(sender)) return;
|
||||
|
||||
// Warn about people trying to whisper a player with the
|
||||
// whisper_friends_only option enabled.
|
||||
if (whisper &&
|
||||
preferences::whisper_friends_only() &&
|
||||
sender != "server" &&
|
||||
sender.find(' ') == std::string::npos && // "server message from foo"
|
||||
!preferences::is_friend(sender))
|
||||
{
|
||||
LOG_NW << "Accepting whispers from friends only, ignored whisper from " << sender << '\n';
|
||||
|
||||
typedef std::map<std::string, time_t> timetable;
|
||||
timetable::const_iterator i = whisper_warnings_.find(sender);
|
||||
|
||||
time_t last_warning = 0;
|
||||
const time_t cur_time = time(nullptr);
|
||||
static const time_t warning_duration = 5 * 60;
|
||||
|
||||
if (i != whisper_warnings_.end()) {
|
||||
last_warning = i->second;
|
||||
}
|
||||
|
||||
//
|
||||
// Don't warn if it's been less than warning_duration seconds since
|
||||
// the last warning. Also, make sure the clock isn't running backwards,
|
||||
// warn anyway if it is.
|
||||
//
|
||||
// We don't need to hande the case where preferences change between
|
||||
// whispers because the lobby instance gets recreated along with the
|
||||
// table after closing the preferences dialog.
|
||||
//
|
||||
if (last_warning && last_warning < cur_time && cur_time - last_warning < warning_duration) {
|
||||
return;
|
||||
}
|
||||
|
||||
utils::string_map symbols;
|
||||
symbols["sender"] = sender;
|
||||
|
||||
chat_.add_message(cur_time,
|
||||
"server",
|
||||
VGETTEXT("$sender is messaging you, and you accept whispers from friends only.", symbols));
|
||||
chat_.update_textbox(chat_textbox_);
|
||||
|
||||
whisper_warnings_[sender] = cur_time;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
preferences::parse_admin_authentication(sender, message);
|
||||
|
||||
bool is_lobby = dynamic_cast<mp::lobby*>(this) != nullptr;
|
||||
|
||||
if (whisper || utils::word_match(message, preferences::login())) {
|
||||
mp_ui_alerts::private_message(is_lobby, sender, message);
|
||||
} else if (preferences::is_friend(sender)) {
|
||||
mp_ui_alerts::friend_message(is_lobby, sender, message);
|
||||
} else if (sender == "server") {
|
||||
mp_ui_alerts::server_message(is_lobby, sender, message);
|
||||
} else {
|
||||
mp_ui_alerts::public_message(is_lobby, sender, message);
|
||||
}
|
||||
|
||||
std::string prefix;
|
||||
|
||||
if(whisper) {
|
||||
utils::string_map symbols;
|
||||
symbols["sender"] = msg["sender"].str();
|
||||
prefix = VGETTEXT("whisper: $sender", symbols);
|
||||
}
|
||||
else {
|
||||
prefix = msg["sender"].str();
|
||||
}
|
||||
|
||||
if (!room.empty()) room = room + ": ";
|
||||
|
||||
chat_.add_message(time(nullptr), room + prefix, msg["message"]);
|
||||
chat_.update_textbox(chat_textbox_);
|
||||
|
||||
config temp = msg;
|
||||
temp["whisper"] = whisper;
|
||||
plugins_manager::get()->notify_event("chat", temp); //notify plugins of the network message
|
||||
}
|
||||
|
||||
void ui::process_network_data(const config& data)
|
||||
{
|
||||
if (const config &error = data.child("error")) {
|
||||
throw wesnothd_error(error["message"]);
|
||||
} else if (const config &message = data.child("message")) {
|
||||
process_message(message);
|
||||
} else if (const config &whisper = data.child("whisper")) {
|
||||
process_message(whisper, true);
|
||||
} else if(data.child("gamelist")) {
|
||||
const cursor::setter cursor_setter(cursor::WAIT);
|
||||
gamelist_initialized_ = true;
|
||||
gamelist_ = data;
|
||||
gamelist_updated(false);
|
||||
gamelist_refresh_ = false;
|
||||
lobby_clock_ = SDL_GetTicks();
|
||||
} else if (const config &gamelist_diff = data.child("gamelist_diff")) {
|
||||
if(gamelist_initialized_) {
|
||||
try {
|
||||
gamelist_.apply_diff(gamelist_diff);
|
||||
} catch(config::error& e) {
|
||||
ERR_CF << "Error while applying the gamelist diff: '"
|
||||
<< e.message << "' Getting a new gamelist.\n";
|
||||
send_to_server(config("refresh_lobby"));
|
||||
}
|
||||
gamelist_refresh_ = true;
|
||||
}
|
||||
} else if (const config &room_join = data.child("room_join")) {
|
||||
if (room_join["player"] == preferences::login()) {
|
||||
chat_.add_message(time(nullptr), "server",
|
||||
"You have joined the room '" + room_join["room"].str() + "'");
|
||||
} else {
|
||||
chat_.add_message(time(nullptr), "server",
|
||||
room_join["player"].str() + " has joined the room '" + room_join["room"].str() + "'");
|
||||
}
|
||||
chat_.update_textbox(chat_textbox_);
|
||||
} else if (const config &room_part = data.child("room_part")) {
|
||||
if (room_part["player"] == preferences::login()) {
|
||||
chat_.add_message(time(nullptr), "server",
|
||||
"You have left the room '" + room_part["room"].str() + "'");
|
||||
} else {
|
||||
chat_.add_message(time(nullptr), "server",
|
||||
room_part["player"].str() + " has left the room '" + room_part["room"].str() + "'");
|
||||
}
|
||||
chat_.update_textbox(chat_textbox_);
|
||||
} else if (const config &room_query_response = data.child("room_query_response")) {
|
||||
if (const config &ms = room_query_response.child("members")) {
|
||||
std::stringstream ss;
|
||||
ss << "Room " << room_query_response["room"].str() << " members: ";
|
||||
for (const config& m : ms.child_range("member")) {
|
||||
ss << m["name"] << " ";
|
||||
}
|
||||
chat_.add_message(time(nullptr), "server", ss.str());
|
||||
chat_.update_textbox(chat_textbox_);
|
||||
}
|
||||
if (const config &rooms = room_query_response.child("rooms")) {
|
||||
std::stringstream ss;
|
||||
ss << "Rooms: ";
|
||||
for (const config& room : rooms.child_range("room")) {
|
||||
ss << room["name"].str() << "(" << room["size"].str() << ") ";
|
||||
}
|
||||
chat_.add_message(time(nullptr), "server", ss.str());
|
||||
chat_.update_textbox(chat_textbox_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ui::hide_children(bool hide)
|
||||
{
|
||||
title_.hide(hide);
|
||||
chat_textbox_.hide(hide);
|
||||
entry_textbox_.hide(hide);
|
||||
users_menu_.hide(hide);
|
||||
}
|
||||
|
||||
void ui::layout_children(const SDL_Rect& /*rect*/)
|
||||
{
|
||||
title_.set_location(xscale(12) + 8, yscale(38) + 8);
|
||||
umenu_style.set_width(xscale(159));
|
||||
users_menu_.set_width(xscale(159));
|
||||
users_menu_.set_max_width(xscale(159));
|
||||
users_menu_.set_location(xscale(856), yscale(42));
|
||||
users_menu_.set_height(yscale(715));
|
||||
users_menu_.set_max_height(yscale(715));
|
||||
chat_textbox_.set_location(xscale(11) + 4, yscale(573) + 4);
|
||||
chat_textbox_.set_measurements(xscale(833) - 8, yscale(143) - 8);
|
||||
entry_textbox_.set_location(xscale(11) + 4, yscale(732));
|
||||
entry_textbox_.set_width(xscale(833) - 8);
|
||||
}
|
||||
|
||||
bool ui::user_info::operator> (const user_info& b) const
|
||||
{
|
||||
//FIXME: to cmpare names, use translation::compare from gettext.hpp
|
||||
user_info const& a = *this;
|
||||
|
||||
// ME always on top
|
||||
if (a.relation == ME) {
|
||||
return true;
|
||||
}
|
||||
if (b.relation == ME) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// friends next, sorted by location
|
||||
if ((a.relation == FRIEND) && (b.relation == FRIEND)) {
|
||||
if (a.state != b.state) {
|
||||
return a.state < b.state;
|
||||
}
|
||||
return a.name < b.name;
|
||||
}
|
||||
if (a.relation == FRIEND) {
|
||||
return true;
|
||||
}
|
||||
if (b.relation == FRIEND) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// players in the selected game next, sorted by relation (friends/neutral/ignored)
|
||||
if ((a.state == SEL_GAME) && (b.state == SEL_GAME)) {
|
||||
if (a.relation != b.relation) {
|
||||
return a.relation < b.relation;
|
||||
}
|
||||
return a.name < b.name;
|
||||
}
|
||||
if (a.state == SEL_GAME) {
|
||||
return true;
|
||||
}
|
||||
if (b.state == SEL_GAME) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// all others grouped by relation
|
||||
if (a.relation != b.relation) {
|
||||
return a.relation < b.relation;
|
||||
}
|
||||
if (a.state != b.state) {
|
||||
return a.state < b.state;
|
||||
}
|
||||
return a.name < b.name;
|
||||
}
|
||||
|
||||
void ui::gamelist_updated(bool silent)
|
||||
{
|
||||
std::list<user_info> u_list;
|
||||
|
||||
for (const config &user : gamelist_.child_range("user"))
|
||||
{
|
||||
user_info u_elem;
|
||||
u_elem.name = user["name"].str();
|
||||
u_elem.state = user["available"].to_bool(true) ? LOBBY : GAME;
|
||||
u_elem.registered = user["registered"].to_bool();
|
||||
u_elem.game_id = user["game_id"].str();
|
||||
u_elem.location = user["location"].str();
|
||||
if (!u_elem.game_id.empty() && u_elem.game_id == selected_game_) {
|
||||
u_elem.state = SEL_GAME;
|
||||
}
|
||||
if (u_elem.name == preferences::login()) {
|
||||
u_elem.relation = ME;
|
||||
} else if (preferences::is_ignored(u_elem.name)) {
|
||||
u_elem.relation = IGNORED;
|
||||
} else if (preferences::is_friend(u_elem.name)) {
|
||||
u_elem.relation = FRIEND;
|
||||
} else {
|
||||
u_elem.relation = NEUTRAL;
|
||||
}
|
||||
u_list.push_back(u_elem);
|
||||
}
|
||||
|
||||
if (preferences::sort_list()) {
|
||||
u_list.sort(std::greater<user_info>());
|
||||
}
|
||||
|
||||
// can't use the bold tag here until the menu code
|
||||
// calculates a correct ellipsis for it
|
||||
const std::string lobby_color_tag = "";
|
||||
const std::string ingame_color_tag = "#";
|
||||
const std::string selgame_color_tag = "<0,191,255>";
|
||||
|
||||
// for now I just disregard the above till I know something better,
|
||||
// it works for me anyways
|
||||
const std::string registered_user_tag = "~";
|
||||
|
||||
const std::string imgpre = IMAGE_PREFIX + std::string("misc/status-");
|
||||
std::vector<std::string> user_strings;
|
||||
std::vector<std::string> menu_strings;
|
||||
|
||||
std::list<user_info>::const_iterator u_itor = u_list.begin();
|
||||
while (u_itor != u_list.end()) {
|
||||
const std::string name_str = u_itor->name +
|
||||
((u_itor->state == LOBBY) ? "" : " (" + u_itor->location + ")");
|
||||
std::string img_str = "";
|
||||
std::string color_str = "";
|
||||
std::string reg_str = "";
|
||||
switch (u_itor->state) {
|
||||
case LOBBY: color_str = lobby_color_tag; break;
|
||||
case GAME: color_str = ingame_color_tag; break;
|
||||
case SEL_GAME: color_str = selgame_color_tag; break;
|
||||
}
|
||||
if (preferences::iconize_list()) {
|
||||
switch (u_itor->relation) {
|
||||
case NEUTRAL: img_str = imgpre + "neutral.png" + IMG_TEXT_SEPARATOR; break;
|
||||
case IGNORED: img_str = imgpre + "ignore.png" + IMG_TEXT_SEPARATOR; break;
|
||||
case FRIEND: img_str = imgpre + "friend.png" + IMG_TEXT_SEPARATOR; break;
|
||||
case ME: img_str = imgpre + "self.png" + IMG_TEXT_SEPARATOR; break;
|
||||
}
|
||||
}
|
||||
reg_str = u_itor->registered ? registered_user_tag : "";
|
||||
user_strings.push_back(u_itor->name);
|
||||
menu_strings.push_back(img_str + reg_str + color_str + name_str + HELP_STRING_SEPARATOR + name_str);
|
||||
++u_itor;
|
||||
}
|
||||
|
||||
set_user_list(user_strings, silent);
|
||||
set_user_menu_items(menu_strings);
|
||||
}
|
||||
|
||||
void ui::set_selected_game(const std::string& game_id)
|
||||
{
|
||||
// reposition the player list to show the players in the selected game
|
||||
if (preferences::sort_list() && (selected_game_ != game_id)) {
|
||||
users_menu_.move_selection(0);
|
||||
}
|
||||
selected_game_ = game_id;
|
||||
}
|
||||
|
||||
void ui::set_user_menu_items(const std::vector<std::string>& list)
|
||||
{
|
||||
users_menu_.set_items(list,true,true);
|
||||
|
||||
// Try to keep selected player
|
||||
std::vector<std::string>::const_iterator i =
|
||||
std::find(user_list_.begin(), user_list_.end(), selected_user_);
|
||||
if(i != user_list_.end()) {
|
||||
users_menu_.move_selection_keeping_viewport(i - user_list_.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void ui::set_user_list(const std::vector<std::string>& list, bool silent)
|
||||
{
|
||||
if(!silent) {
|
||||
bool is_lobby = dynamic_cast<mp::lobby*>(this) != nullptr;
|
||||
|
||||
if(list.size() < user_list_.size()) {
|
||||
mp_ui_alerts::player_leaves(is_lobby);
|
||||
} else if(list.size() > user_list_.size()) {
|
||||
mp_ui_alerts::player_joins(is_lobby);
|
||||
}
|
||||
}
|
||||
|
||||
user_list_ = list;
|
||||
}
|
||||
|
||||
std::string ui::get_selected_user_game()
|
||||
{
|
||||
const config &u = gamelist_.find_child("user", "name", selected_user_);
|
||||
if (u) return u["game_id"];
|
||||
return std::string();
|
||||
}
|
||||
|
||||
void ui::append_to_title(const std::string& text) {
|
||||
title_.set_text(title_.get_text() + text);
|
||||
}
|
||||
|
||||
const gui::label& ui::title() const
|
||||
{
|
||||
return title_;
|
||||
}
|
||||
|
||||
plugins_context * ui::get_plugins_context()
|
||||
{
|
||||
return plugins_context_.get();
|
||||
}
|
||||
|
||||
void ui::send_to_server(const config& cfg)
|
||||
{
|
||||
if (wesnothd_connection_) {
|
||||
wesnothd_connection_->send_data(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
bool ui::receive_from_server(config& cfg)
|
||||
{
|
||||
return wesnothd_connection_ && wesnothd_connection_->receive_data(cfg);
|
||||
}
|
||||
|
||||
}// namespace mp
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 - 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 MULTIPLAYER_UI_HPP_INCLUDED
|
||||
#define MULTIPLAYER_UI_HPP_INCLUDED
|
||||
|
||||
#include "chat_events.hpp"
|
||||
#include "floating_label.hpp"
|
||||
#include "hotkey/command_executor.hpp"
|
||||
#include "preferences_display.hpp"
|
||||
#include "scripting/plugins/context.hpp"
|
||||
#include "widgets/combo.hpp"
|
||||
#include "widgets/label.hpp"
|
||||
#include "widgets/menu.hpp"
|
||||
#include "widgets/textbox.hpp"
|
||||
|
||||
#include <deque>
|
||||
|
||||
class display;
|
||||
class game_display;
|
||||
class config;
|
||||
class plugins_context;
|
||||
|
||||
class wesnothd_connection;
|
||||
namespace mp {
|
||||
|
||||
std::string get_color_string(int id);
|
||||
std::string get_color_string(const std::string& id);
|
||||
|
||||
/** this class memorizes a chat session. */
|
||||
class chat
|
||||
{
|
||||
public:
|
||||
chat();
|
||||
|
||||
void add_message(const time_t& time, const std::string& user,
|
||||
const std::string& message);
|
||||
|
||||
void init_textbox(gui::textbox& textbox);
|
||||
void update_textbox(gui::textbox& textbox);
|
||||
|
||||
void clear_history();
|
||||
|
||||
private:
|
||||
struct msg {
|
||||
msg(const time_t& time, const std::string& user, const std::string& message)
|
||||
: time(time), user(user), message(message) {}
|
||||
time_t time;
|
||||
std::string user;
|
||||
std::string message;
|
||||
};
|
||||
typedef std::deque<msg> msg_hist;
|
||||
|
||||
std::string format_message(const msg& message);
|
||||
SDL_Color color_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, private events::chat_handler, private font::floating_label_context
|
||||
{
|
||||
public:
|
||||
enum result { CONTINUE, JOIN, OBSERVE, CREATE, LOAD_GAME, PREFERENCES,
|
||||
PLAY, QUIT };
|
||||
|
||||
ui(CVideo& v, wesnothd_connection* connection, const std::string& title,
|
||||
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) override;
|
||||
using widget::set_location;
|
||||
const std::vector<std::string>& user_list() const { return user_list_; }
|
||||
void send_to_server(const config& cfg) override;
|
||||
bool receive_from_server(config& dst);
|
||||
protected:
|
||||
int xscale(int x) const;
|
||||
int yscale(int y) const;
|
||||
static const int xscale_base;
|
||||
static const int yscale_base;
|
||||
|
||||
SDL_Rect client_area() const;
|
||||
|
||||
CVideo& video_;
|
||||
wesnothd_connection* wesnothd_connection_;
|
||||
CVideo& video() { return video_; }
|
||||
|
||||
/**
|
||||
* 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() override;
|
||||
|
||||
virtual void process_event() override;
|
||||
|
||||
virtual void handle_event(const SDL_Event& event) override;
|
||||
virtual void handle_key_event(const SDL_KeyboardEvent& event);
|
||||
|
||||
/** Override chat_handler. */
|
||||
void add_chat_message(const time_t& time, const std::string& speaker,
|
||||
int side, const std::string& message,
|
||||
events::chat_handler::MESSAGE_TYPE type=events::chat_handler::MESSAGE_PRIVATE) override;
|
||||
void send_chat_message(const std::string& message, bool allies_only=false) override;
|
||||
|
||||
/** Process chat messages. */
|
||||
void process_message(const config& msg, const bool whisper=false);
|
||||
|
||||
/**
|
||||
* Processes any pending network data. Called by the public
|
||||
* process_network() method. Overridden by subclasses who add more
|
||||
* behavior for network.
|
||||
*/
|
||||
virtual void process_network_data(const config& data);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Sets the name of the selected game which is used to highlight the names
|
||||
* of the players which have joined this game.
|
||||
*/
|
||||
void set_selected_game(const std::string& game_name);
|
||||
|
||||
/**
|
||||
* Called each time the gamelist_ variable is updated. May be
|
||||
* overridden by child classes to add custom gamelist behavior.
|
||||
*/
|
||||
virtual void gamelist_updated(bool silent=true);
|
||||
|
||||
/** Sets the user list */
|
||||
void set_user_list(const std::vector<std::string>&, bool silent);
|
||||
void set_user_menu_items(const std::vector<std::string>& list);
|
||||
|
||||
/** Returns the current gamelist */
|
||||
config& gamelist() { return gamelist_; }
|
||||
|
||||
void append_to_title(const std::string& name);
|
||||
const gui::label& title() const;
|
||||
|
||||
std::string get_selected_user_game();
|
||||
bool selected_user_changed() const { return selected_user_changed_; }
|
||||
void set_selected_user_changed(const bool& changed) { selected_user_changed_ = changed; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* Set to true when the widgets are initialized. Allows delayed
|
||||
* initialization on first positioning.
|
||||
*/
|
||||
bool initialized_;
|
||||
bool gamelist_initialized_;
|
||||
|
||||
/**
|
||||
* 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::label title_;
|
||||
gui::textbox entry_textbox_;
|
||||
gui::textbox chat_textbox_;
|
||||
|
||||
gui::menu users_menu_;
|
||||
|
||||
std::vector<std::string> user_list_;
|
||||
|
||||
std::string selected_game_;
|
||||
|
||||
std::string selected_user_;
|
||||
bool selected_user_changed_;
|
||||
|
||||
result result_;
|
||||
|
||||
bool gamelist_refresh_;
|
||||
|
||||
Uint32 lobby_clock_;
|
||||
|
||||
std::map<std::string, time_t> whisper_warnings_;
|
||||
|
||||
public:
|
||||
enum user_relation { ME, FRIEND, NEUTRAL, IGNORED };
|
||||
enum user_state { LOBBY, GAME, SEL_GAME };
|
||||
|
||||
private:
|
||||
struct user_info
|
||||
{
|
||||
user_info() :
|
||||
name(),
|
||||
game_id(),
|
||||
location(),
|
||||
relation(ME),
|
||||
state(LOBBY),
|
||||
registered()
|
||||
{
|
||||
}
|
||||
|
||||
std::string name;
|
||||
std::string game_id;
|
||||
std::string location;
|
||||
user_relation relation;
|
||||
user_state state;
|
||||
/** True if this user is registered on the server. */
|
||||
bool registered;
|
||||
bool operator> (const user_info& b) const;
|
||||
};
|
||||
|
||||
protected:
|
||||
std::unique_ptr<plugins_context> plugins_context_;
|
||||
public:
|
||||
plugins_context * get_plugins_context();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,537 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 - 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.
|
||||
*/
|
||||
|
||||
#include "global.hpp"
|
||||
|
||||
#include "construct_dialog.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "game_config_manager.hpp"
|
||||
#include "game_preferences.hpp"
|
||||
#include "gui/dialogs/multiplayer/faction_select.hpp"
|
||||
#include "gui/dialogs/transient_message.hpp"
|
||||
#include "gui/dialogs/network_transmission.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "image.hpp"
|
||||
#include "log.hpp"
|
||||
#include "font/marked-up_text.hpp"
|
||||
#include "font/standard_colors.hpp"
|
||||
#include "game_initialization/mp_game_utils.hpp"
|
||||
#include "game_initialization/multiplayer_wait.hpp"
|
||||
#include "statistics.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include "mp_ui_alerts.hpp"
|
||||
#include "scripting/plugins/context.hpp"
|
||||
#include "sdl/rect.hpp"
|
||||
#include "units/types.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
#include "wml_separators.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "video.hpp"
|
||||
|
||||
#include "utils/functional.hpp"
|
||||
|
||||
static lg::log_domain log_network("network");
|
||||
#define DBG_NW LOG_STREAM(debug, log_network)
|
||||
#define LOG_NW LOG_STREAM(info, log_network)
|
||||
|
||||
static lg::log_domain log_enginerefac("enginerefac");
|
||||
#define LOG_RG LOG_STREAM(info, log_enginerefac)
|
||||
#define ERR_RG LOG_STREAM(err, log_enginerefac)
|
||||
|
||||
static lg::log_domain log_mp("mp/main");
|
||||
#define DBG_MP LOG_STREAM(debug, log_mp)
|
||||
#define ERR_MP LOG_STREAM(err, log_mp)
|
||||
|
||||
|
||||
namespace mp {
|
||||
|
||||
wait::wait(CVideo& v, wesnothd_connection* connection, const config& cfg, saved_game& state,
|
||||
mp::chat& c, config& gamelist, const bool first_scenario) :
|
||||
ui(v, connection, _("Game Lobby"), cfg, c, gamelist),
|
||||
cancel_button_(video(), first_scenario ? _("Cancel") : _("Quit")),
|
||||
start_label_(video(), _("Waiting for game to start..."), font::SIZE_SMALL, font::LOBBY_COLOR),
|
||||
game_menu_(video(), std::vector<std::string>(), false, -1, -1, nullptr, &gui::menu::bluebg_style),
|
||||
level_(),
|
||||
state_(state),
|
||||
first_scenario_(first_scenario),
|
||||
stop_updates_(false)
|
||||
{
|
||||
game_menu_.set_numeric_keypress_selection(false);
|
||||
gamelist_updated();
|
||||
|
||||
plugins_context_.reset(new plugins_context("Multiplayer Wait"));
|
||||
|
||||
//These structure initializers create a lobby::process_data_event
|
||||
plugins_context_->set_callback("quit", std::bind(&wait::process_event_impl, this, true), false);
|
||||
plugins_context_->set_callback("chat", [this](const config& cfg) { send_chat_message(cfg["message"], false); }, true);
|
||||
}
|
||||
|
||||
wait::~wait()
|
||||
{
|
||||
try {
|
||||
if (get_result() == QUIT) {
|
||||
state_ = saved_game();
|
||||
state_.classification().campaign_type = game_classification::CAMPAIGN_TYPE::MULTIPLAYER;
|
||||
}
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
void wait::process_event()
|
||||
{
|
||||
process_event_impl(cancel_button_.pressed());
|
||||
}
|
||||
|
||||
void wait::process_event_impl(bool quit)
|
||||
{
|
||||
if (quit) {
|
||||
set_result(QUIT);
|
||||
}
|
||||
}
|
||||
|
||||
void wait::join_game(bool observe)
|
||||
{
|
||||
const bool download_res = download_level_data();
|
||||
if (!download_res) {
|
||||
DBG_MP << "mp wait: could not download level data, quitting...";
|
||||
set_result(QUIT);
|
||||
return;
|
||||
} else if (level_["started"].to_bool()) {
|
||||
set_result(PLAY);
|
||||
return;
|
||||
}
|
||||
|
||||
if (first_scenario_) {
|
||||
state_ = saved_game();
|
||||
state_.classification() = game_classification(level_);
|
||||
|
||||
if(state_.classification().campaign_type != game_classification::CAMPAIGN_TYPE::MULTIPLAYER) {
|
||||
ERR_MP << "Mp wait recieved a game that is not a multiplayer game\n";
|
||||
}
|
||||
// Make sure that we have the same config as host, if possible.
|
||||
game_config_manager::get()->load_game_config_for_game(state_.classification());
|
||||
}
|
||||
|
||||
// Add the map name to the title.
|
||||
append_to_title(": " + get_scenario()["name"].t_str());
|
||||
|
||||
game_config::add_color_info(get_scenario());
|
||||
if (!observe) {
|
||||
//search for an appropriate vacant slot. If a description is set
|
||||
//(i.e. we're loading from a saved game), then prefer to get the side
|
||||
//with the same description as our login. Otherwise just choose the first
|
||||
//available side.
|
||||
const config *side_choice = nullptr;
|
||||
int side_num = -1, nb_sides = 0;
|
||||
for (const config &sd : get_scenario().child_range("side"))
|
||||
{
|
||||
DBG_MP << "*** side " << nb_sides << "***\n" << sd.debug() << "***\n";
|
||||
|
||||
if (sd["controller"] == "reserved" && sd["current_player"] == preferences::login())
|
||||
{
|
||||
side_choice = &sd;
|
||||
side_num = nb_sides;
|
||||
break;
|
||||
}
|
||||
if (sd["controller"] == "human" && sd["player_id"].empty())
|
||||
{
|
||||
if (!side_choice) { // found the first empty side
|
||||
side_choice = &sd;
|
||||
side_num = nb_sides;
|
||||
}
|
||||
if (sd["current_player"] == preferences::login()) {
|
||||
side_choice = &sd;
|
||||
side_num = nb_sides;
|
||||
break; // found the preferred one
|
||||
}
|
||||
}
|
||||
if (sd["player_id"] == preferences::login())
|
||||
{
|
||||
//We already own a side in this game.
|
||||
generate_menu();
|
||||
return;
|
||||
}
|
||||
++nb_sides;
|
||||
}
|
||||
if (!side_choice) {
|
||||
DBG_MP << "could not find a side, all " << get_scenario().child_count("side") << " sides were unsuitable\n";
|
||||
set_result(QUIT);
|
||||
return;
|
||||
}
|
||||
|
||||
bool allow_changes = (*side_choice)["allow_changes"].to_bool(true);
|
||||
|
||||
//if the client is allowed to choose their team, instead of having
|
||||
//it set by the server, do that here.
|
||||
if(allow_changes) {
|
||||
events::event_context context;
|
||||
|
||||
const config &era = level_.child("era");
|
||||
/** @todo Check whether we have the era. If we don't inform the user. */
|
||||
if (!era)
|
||||
throw config::error(_("No era information found."));
|
||||
config::const_child_itors possible_sides = era.child_range("multiplayer_side");
|
||||
if (possible_sides.empty()) {
|
||||
set_result(QUIT);
|
||||
throw config::error(_("No multiplayer sides found"));
|
||||
}
|
||||
|
||||
const std::string color = (*side_choice)["color"].str();
|
||||
|
||||
std::vector<const config*> era_factions;
|
||||
for (const config &side : possible_sides) {
|
||||
era_factions.push_back(&side);
|
||||
}
|
||||
|
||||
const bool is_mp = state_.classification().is_normal_mp_game();
|
||||
const bool lock_settings =
|
||||
get_scenario()["force_lock_settings"].to_bool(!is_mp);
|
||||
const bool use_map_settings =
|
||||
level_.child("multiplayer")["mp_use_map_settings"].to_bool();
|
||||
const bool saved_game =
|
||||
level_.child("multiplayer")["savegame"].to_bool();
|
||||
|
||||
ng::flg_manager flg(era_factions, *side_choice, lock_settings, use_map_settings,
|
||||
saved_game);
|
||||
|
||||
std::vector<std::string> choices;
|
||||
for (const config *s : flg.choosable_factions())
|
||||
{
|
||||
const config &side = *s;
|
||||
const std::string &name = side["name"];
|
||||
const std::string &icon = side["image"];
|
||||
|
||||
if (!icon.empty()) {
|
||||
std::string rgb = side["flag_rgb"];
|
||||
if (rgb.empty())
|
||||
rgb = "magenta";
|
||||
|
||||
choices.push_back(IMAGE_PREFIX + icon + "~RC(" + rgb + ">" +
|
||||
color + ")" + COLUMN_SEPARATOR + name);
|
||||
} else {
|
||||
choices.push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
gui2::dialogs::faction_select dlg(flg, color, side_num + 1);
|
||||
dlg.show(video());
|
||||
|
||||
if(dlg.get_retval() != gui2::window::OK) {
|
||||
set_result(QUIT);
|
||||
return;
|
||||
}
|
||||
|
||||
config faction;
|
||||
config& change = faction.add_child("change_faction");
|
||||
change["change_faction"] = true;
|
||||
change["name"] = preferences::login();
|
||||
change["faction"] = flg.current_faction()["id"];
|
||||
change["leader"] = flg.current_leader();
|
||||
change["gender"] = flg.current_gender();
|
||||
send_to_server(faction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
generate_menu();
|
||||
}
|
||||
|
||||
void wait::start_game()
|
||||
{
|
||||
if (const config &stats = level_.child("statistics")) {
|
||||
statistics::fresh_stats();
|
||||
statistics::read_stats(stats);
|
||||
}
|
||||
level_to_gamestate(level_, state_);
|
||||
|
||||
LOG_NW << "starting game\n";
|
||||
mp_ui_alerts::game_has_begun();
|
||||
}
|
||||
|
||||
void wait::layout_children(const SDL_Rect& rect)
|
||||
{
|
||||
ui::layout_children(rect);
|
||||
|
||||
const SDL_Rect ca = client_area();
|
||||
int y = ca.y + ca.h - cancel_button_.height();
|
||||
|
||||
game_menu_.set_location(ca.x, ca.y + title().height());
|
||||
game_menu_.set_measurements(ca.w, y - ca.y - title().height()
|
||||
- gui::ButtonVPadding);
|
||||
game_menu_.set_max_width(ca.w);
|
||||
game_menu_.set_max_height(y - ca.y - title().height() - gui::ButtonVPadding);
|
||||
cancel_button_.set_location(ca.x + ca.w - cancel_button_.width(), y);
|
||||
start_label_.set_location(ca.x, y + 4);
|
||||
}
|
||||
|
||||
void wait::hide_children(bool hide)
|
||||
{
|
||||
ui::hide_children(hide);
|
||||
|
||||
cancel_button_.hide(hide);
|
||||
game_menu_.hide(hide);
|
||||
}
|
||||
|
||||
void wait::process_network_data(const config& data)
|
||||
{
|
||||
ui::process_network_data(data);
|
||||
|
||||
if(!data["message"].empty()) {
|
||||
gui2::show_transient_message(video()
|
||||
, _("Response")
|
||||
, data["message"]);
|
||||
}
|
||||
if (data["failed"].to_bool()) {
|
||||
set_result(QUIT);
|
||||
return;
|
||||
} else if(data.child("stop_updates")) {
|
||||
stop_updates_ = true;
|
||||
} else if(data.child("start_game")) {
|
||||
LOG_NW << "received start_game message\n";
|
||||
set_result(PLAY);
|
||||
return;
|
||||
} else if(data.child("leave_game")) {
|
||||
set_result(QUIT);
|
||||
return;
|
||||
} else if (const config &c = data.child("scenario_diff")) {
|
||||
LOG_NW << "received diff for scenario... applying...\n";
|
||||
/** @todo We should catch config::error and then leave the game. */
|
||||
level_.apply_diff(c);
|
||||
generate_menu();
|
||||
} else if(const config &change = data.child("change_controller")) {
|
||||
LOG_NW << "received change controller" << std::endl;
|
||||
LOG_RG << "multiplayer_wait: [change_controller]" << std::endl;
|
||||
LOG_RG << data.debug() << std::endl;
|
||||
//const int side = std::stoi(change["side"]);
|
||||
|
||||
if (config & sidetochange = get_scenario().find_child("side", "side", change["side"])) {
|
||||
LOG_RG << "found side : " << sidetochange.debug() << std::endl;
|
||||
sidetochange.merge_with(change);
|
||||
LOG_RG << "changed to : " << sidetochange.debug() << std::endl;
|
||||
} else {
|
||||
LOG_RG << "change_controller didn't find any side!" << std::endl;
|
||||
}
|
||||
} else if(data.has_child("scenario") || data.has_child("snapshot") || data.child("next_scenario")) {
|
||||
level_ = first_scenario_ ? data : data.child("next_scenario");
|
||||
LOG_NW << "got some sides. Current number of sides = "
|
||||
<< get_scenario().child_count("side") << ','
|
||||
<< data.child_count("side") << '\n';
|
||||
generate_menu();
|
||||
}
|
||||
}
|
||||
|
||||
static std::string generate_user_description(const config& side)
|
||||
{
|
||||
//allow the host to overwrite it, this is needed because only the host knows the ai_algorithm.
|
||||
if(const config::attribute_value* desc = side.get("user_description")) {
|
||||
return desc->str();
|
||||
}
|
||||
|
||||
std::string controller_type = side["controller"].str();
|
||||
std::string reservation = side["reserved_for"].str();
|
||||
std::string owner = side["player_id"].str();
|
||||
|
||||
if(controller_type == "ai") {
|
||||
return _("Computer Player");
|
||||
}
|
||||
else if (controller_type == "null") {
|
||||
return _("(Empty slot)");
|
||||
}
|
||||
else if (controller_type == "reserved") {
|
||||
utils::string_map symbols;
|
||||
symbols["playername"] = reservation;
|
||||
return vgettext("(Reserved for $playername)",symbols);
|
||||
}
|
||||
else if(owner.empty()) {
|
||||
return _("(Vacant slot)");
|
||||
}
|
||||
else if (controller_type == "human" || controller_type == "network") {
|
||||
return owner;
|
||||
}
|
||||
else {
|
||||
ERR_RG << "Found unknown controller type:" << controller_type << std::endl;
|
||||
return _("(empty)");
|
||||
}
|
||||
}
|
||||
|
||||
void wait::generate_menu()
|
||||
{
|
||||
if (stop_updates_)
|
||||
return;
|
||||
|
||||
std::vector<std::string> details;
|
||||
std::set<std::string> playerlist;
|
||||
|
||||
for (const config &sd : get_scenario().child_range("side"))
|
||||
{
|
||||
if (!sd["allow_player"].to_bool(true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string description = generate_user_description(sd);
|
||||
|
||||
t_string side_name = sd["faction_name"];
|
||||
std::string leader_type = sd["type"];
|
||||
std::string gender_id = sd["gender"];
|
||||
|
||||
// Hack: if there is a unit which can recruit, use it as a
|
||||
// leader. Necessary to display leader information when loading
|
||||
// saves.
|
||||
for (const config &side_unit : sd.child_range("unit"))
|
||||
{
|
||||
if (side_unit["canrecruit"].to_bool()) {
|
||||
leader_type = side_unit["type"].str();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!sd["player_id"].empty())
|
||||
playerlist.insert(sd["player_id"]);
|
||||
|
||||
std::string leader_name;
|
||||
std::string leader_image;
|
||||
|
||||
const unit_type *ut = unit_types.find(leader_type);
|
||||
|
||||
if (ut) {
|
||||
const unit_type &utg = ut->get_gender_unit_type(gender_id);
|
||||
|
||||
leader_name = utg.type_name();
|
||||
std::string RCcolor = sd["color"];
|
||||
|
||||
if (RCcolor.empty())
|
||||
RCcolor = sd["side"].str();
|
||||
leader_image = utg.image() + std::string("~RC(") + utg.flag_rgb() + ">" + RCcolor + ")";
|
||||
} else {
|
||||
leader_image = ng::random_enemy_picture;
|
||||
}
|
||||
if (!leader_image.empty()) {
|
||||
// Dumps the "image" part of the faction name, if any,
|
||||
// to replace it by a picture of the actual leader
|
||||
if(side_name.str()[0] == font::IMAGE) {
|
||||
std::string::size_type p =
|
||||
side_name.str().find_first_of(COLUMN_SEPARATOR);
|
||||
if(p != std::string::npos && p < side_name.size()) {
|
||||
side_name = IMAGE_PREFIX + leader_image + COLUMN_SEPARATOR + side_name.str().substr(p+1);
|
||||
}
|
||||
} else {
|
||||
// no image prefix, just add the leader image
|
||||
// (assuming that there is also no COLUMN_SEPARATOR)
|
||||
side_name = IMAGE_PREFIX + leader_image + COLUMN_SEPARATOR + side_name.str();
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream str;
|
||||
str << sd["side"] << ". " << COLUMN_SEPARATOR;
|
||||
str << description << COLUMN_SEPARATOR << side_name << COLUMN_SEPARATOR;
|
||||
// Mark parentheses translatable for languages like Japanese
|
||||
if(!leader_name.empty())
|
||||
str << _("(") << leader_name << _(")");
|
||||
str << COLUMN_SEPARATOR;
|
||||
// Don't show gold for saved games
|
||||
if (sd["allow_changes"].to_bool())
|
||||
str << sd["gold"] << ' ' << _n("multiplayer_starting_gold^Gold", "multiplayer_starting_gold^Gold", sd["gold"].to_int()) << COLUMN_SEPARATOR;
|
||||
|
||||
int income_amt = sd["income"];
|
||||
if(income_amt != 0){
|
||||
str << _("(") << _("Income") << ' ';
|
||||
if(income_amt > 0)
|
||||
str << _("+");
|
||||
str << sd["income"] << _(")");
|
||||
}
|
||||
|
||||
str << COLUMN_SEPARATOR << t_string::from_serialized(sd["user_team_name"].str());
|
||||
|
||||
str << COLUMN_SEPARATOR << get_color_string(sd["color"].str());
|
||||
details.push_back(str.str());
|
||||
}
|
||||
|
||||
game_menu_.set_items(details);
|
||||
|
||||
// Uses the actual connected player list if we do not have any
|
||||
// "gamelist" user data
|
||||
if (!gamelist().child("user")) {
|
||||
set_user_list(std::vector<std::string>(playerlist.begin(), playerlist.end()), true);
|
||||
}
|
||||
}
|
||||
|
||||
bool wait::download_level_data()
|
||||
{
|
||||
assert(wesnothd_connection_);
|
||||
DBG_MP << "download_level_data()\n";
|
||||
if (!first_scenario_) {
|
||||
// Ask for the next scenario data.
|
||||
send_to_server(config("load_next_scenario"));
|
||||
}
|
||||
bool has_scenario_and_controllers = false;
|
||||
while (!has_scenario_and_controllers) {
|
||||
config revc;
|
||||
bool data_res = gui2::dialogs::network_transmission::wesnothd_receive_dialog(
|
||||
video(), "download level data", revc, *wesnothd_connection_);
|
||||
|
||||
if (!data_res) {
|
||||
DBG_MP << "download_level_data bad results\n";
|
||||
return false;
|
||||
}
|
||||
check_response(data_res, revc);
|
||||
if (revc.child("leave_game")) {
|
||||
return false;
|
||||
}
|
||||
else if(config& next_scenario = revc.child("next_scenario")) {
|
||||
level_.swap(next_scenario);
|
||||
}
|
||||
else if(revc.has_attribute("version")) {
|
||||
level_.swap(revc);
|
||||
has_scenario_and_controllers = true;
|
||||
}
|
||||
else if(config& controllers = revc.child("controllers")) {
|
||||
int index = 0;
|
||||
for (const config& controller : controllers.child_range("controller")) {
|
||||
if(config& side = get_scenario().child("side", index)) {
|
||||
side["is_local"] = controller["is_local"];
|
||||
}
|
||||
++index;
|
||||
}
|
||||
has_scenario_and_controllers = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DBG_MP << "download_level_data() success.\n";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
config& wait::get_scenario()
|
||||
{
|
||||
|
||||
if(config& scenario = level_.child("scenario"))
|
||||
return scenario;
|
||||
else if(config& snapshot = level_.child("snapshot"))
|
||||
return snapshot;
|
||||
else
|
||||
return level_;
|
||||
}
|
||||
|
||||
const config& wait::get_scenario() const
|
||||
{
|
||||
if(const config& scenario = level_.child("scenario"))
|
||||
return scenario;
|
||||
else if(const config& snapshot = level_.child("snapshot"))
|
||||
return snapshot;
|
||||
else
|
||||
return level_;
|
||||
}
|
||||
|
||||
} // namespace mp
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
Copyright (C) 2007 - 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 MULTIPLAYER_WAIT_HPP_INCLUDED
|
||||
#define MULTIPLAYER_WAIT_HPP_INCLUDED
|
||||
|
||||
#include "flg_manager.hpp"
|
||||
#include "multiplayer_ui.hpp"
|
||||
#include "widgets/combo.hpp"
|
||||
#include "show_dialog.hpp" //gui::preview_pane
|
||||
|
||||
namespace mp {
|
||||
|
||||
class wait : public ui
|
||||
{
|
||||
public:
|
||||
wait(CVideo& v, wesnothd_connection* connection, const config& cfg, saved_game& state, chat& c,
|
||||
config& gamelist, const bool first_scenario = true);
|
||||
~wait();
|
||||
virtual void process_event();
|
||||
|
||||
void join_game(bool observe);
|
||||
|
||||
void start_game();
|
||||
|
||||
protected:
|
||||
virtual void layout_children(const SDL_Rect& rect);
|
||||
virtual void hide_children(bool hide=true);
|
||||
virtual void process_network_data(const config& data);
|
||||
|
||||
private:
|
||||
void generate_menu();
|
||||
bool download_level_data();
|
||||
config& get_scenario();
|
||||
const config& get_scenario() const;
|
||||
|
||||
gui::button cancel_button_;
|
||||
gui::label start_label_;
|
||||
gui::menu game_menu_;
|
||||
|
||||
config level_;
|
||||
saved_game& state_;
|
||||
|
||||
const bool first_scenario_;
|
||||
bool stop_updates_;
|
||||
|
||||
void process_event_impl(bool);
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
|
@ -48,6 +48,7 @@
|
|||
#include "game_initialization/create_engine.hpp"
|
||||
#include "game_initialization/playcampaign.hpp" // for play_game, etc
|
||||
#include "preferences.hpp" // for disable_preferences_save, etc
|
||||
#include "preferences_display.hpp"
|
||||
#include "savegame.hpp" // for clean_saves, etc
|
||||
#include "scripting/application_lua_kernel.hpp"
|
||||
#include "sdl/utils.hpp" // for surface
|
||||
|
|
Loading…
Add table
Reference in a new issue