Added GUI2 MP Join Game dialog

Note the faction select dialog doesn't appear for some reason.
This commit is contained in:
Charles Dang 2016-10-01 02:09:20 +11:00
parent fe2e119b25
commit 45ea8c6a43
9 changed files with 1113 additions and 140 deletions

View file

@ -0,0 +1,505 @@
#textdomain wesnoth-lib
###
### Definition of the mp game staging screen
###
#define _GUI_SIDE_LIST
[listbox]
id = "side_list"
definition = "default"
vertical_scrollbar_mode = "always"
horizontal_scrollbar_mode = "never"
[list_definition]
[row]
[column]
horizontal_grow = "true"
vertical_grow = "true"
[toggle_panel]
id = "panel"
definition = "default"
[grid]
[row]
[column]
grow_factor = 0
border = "all"
border_size = 10
horizontal_grow = "true"
vertical_alignment = "top"
[label]
id = "side_number"
definition = "default_large"
linked_group = "side_number"
[/label]
[/column]
[column]
grow_factor = 1
horizontal_grow = "true"
#vertical_grow = "true"
[grid]
linked_group = "leader"
[row]
[column]
grow_factor = 0
horizontal_grow = "true"
border = "all"
border_size = 5
[image]
id = "leader_image"
definition = "default"
[/image]
[/column]
[column]
grow_factor = 1
horizontal_grow = "true"
vertical_grow = "true"
[grid]
[row]
grow_factor = 1
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
[label]
id = "leader_type"
definition = "default_large"
use_markup = "true"
[/label]
[/column]
[/row]
[row]
grow_factor = 0
[column]
horizontal_grow = "true"
#vertical_grow = "true"
[grid]
[row]
[column]
grow_factor = 0
border = "left,bottom"
border_size = 5
[label]
definition = "default_small"
label = _ "<b>Faction:</b>"
use_markup = "true"
[/label]
[/column]
[column]
grow_factor = 1
border = "left,bottom,right"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
[label]
id = "leader_faction"
definition = "default_small"
use_markup = "true"
[/label]
[/column]
[/row]
[row]
[column]
grow_factor = 0
border = "left,bottom"
border_size = 5
[label]
definition = "default_small"
label = _ "<b>Gender:</b>"
use_markup = "true"
[/label]
[/column]
[column]
grow_factor = 1
border = "left,bottom,right"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
[image]
id = "leader_gender"
definition = "default_small"
[/image]
[/column]
[/row]
[/grid]
[/column]
[/row]
[/grid]
[/column]
[/row]
[/grid]
[/column]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
id = "side_team"
definition = "default"
[/label]
[/column]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
id = "side_gold"
definition = "default"
[/label]
[/column]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
id = "side_income"
definition = "default"
[/label]
[/column]
[column]
grow_factor = 0
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
id = "side_color"
definition = "default"
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[/listbox]
#enddef
#define _GUI_CONTROL_AREA
[grid]
[row]
grow_factor = 1
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
vertical_grow = "true"
[listbox]
id = "player_list"
definition = "default"
horizontal_scrollbar_mode = "never"
[list_definition]
[row]
[column]
horizontal_grow = "true"
[toggle_panel]
id = "panel"
definition = "default"
[grid]
[row]
[column]
border = "all"
border_size = 5
horizontal_grow = "true"
[label]
id = "player_name"
definition = "default"
[/label]
[/column]
[/row]
[/grid]
[/toggle_panel]
[/column]
[/row]
[/list_definition]
[/listbox]
[/column]
[/row]
[row]
grow_factor = 0
[column]
[grid]
[row]
[column]
border = "all"
border_size = 5
[button]
id = "ok"
definition = "large"
label = _ "Im Ready"
[/button]
[/column]
[column]
border = "all"
border_size = 5
[button]
id = "cancel"
definition = "large"
label = _ "Cancel"
[/button]
[/column]
[/row]
[/grid]
[/column]
[/row]
[/grid]
#enddef
[window]
id = "mp_join_game"
description = "MP join game."
[resolution]
definition = "borderless"
{GUI_WINDOW_FULLSCREEN}
[linked_group]
id = "side_number"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "controller"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "leader"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "team_and_color"
fixed_width = "true"
[/linked_group]
[linked_group]
id = "gold_and_income"
fixed_width = "true"
[/linked_group]
[tooltip]
id = "tooltip"
[/tooltip]
[helptip]
id = "tooltip"
[/helptip]
[grid]
[row]
grow_factor = 0
[column]
grow_factor = 1
horizontal_alignment = "left"
border = "all"
border_size = 5
[label]
id = "title"
definition = "title"
label = _ "Game Lobby"
[/label]
[/column]
[/row]
[row]
grow_factor = 1
[column]
horizontal_grow = "true"
vertical_grow = "true"
[grid]
[row]
[column]
grow_factor = 1
vertical_grow = "true"
horizontal_grow = "true"
[grid]
[row]
grow_factor = 1
[column]
horizontal_grow = "true"
vertical_grow = "true"
{GUI_FORCE_WIDGET_MINIMUM_SIZE 0 "((screen_height * 55) / 100)" (
border = "all"
border_size = 5
{_GUI_SIDE_LIST}
)}
[/column]
[/row]
[row]
grow_factor = 0
[column]
grow_factor = 1
horizontal_grow = "true"
border = "all"
border_size = 5
[label]
id = "status_label"
definition = "default_small"
label = _ "Waiting for players to join..."
[/label]
[/column]
[/row]
[row]
grow_factor = 0
[column]
horizontal_grow = "true"
vertical_grow = "true"
{GUI_FORCE_WIDGET_MINIMUM_SIZE 0 "((screen_height * 25 / 100))" (
[chatbox]
id = "chat"
[/chatbox]
)}
[/column]
[/row]
[/grid]
[/column]
[column]
grow_factor = 0
horizontal_grow = "true"
vertical_grow = "true"
{_GUI_CONTROL_AREA}
[/column]
[/row]
[/grid]
[/column]
[/row]
[/grid]
[/resolution]
[/window]
#undef _GUI_CONTROL_AREA
#undef _GUI_SIDE_LIST

View file

@ -607,6 +607,8 @@
<Unit filename="../../src/gui/dialogs/multiplayer/mp_create_game_set_password.hpp" />
<Unit filename="../../src/gui/dialogs/multiplayer/mp_host_game_prompt.cpp" />
<Unit filename="../../src/gui/dialogs/multiplayer/mp_host_game_prompt.hpp" />
<Unit filename="../../src/gui/dialogs/multiplayer/mp_join_game.cpp" />
<Unit filename="../../src/gui/dialogs/multiplayer/mp_join_game.hpp" />
<Unit filename="../../src/gui/dialogs/multiplayer/mp_join_game_password_prompt.cpp" />
<Unit filename="../../src/gui/dialogs/multiplayer/mp_join_game_password_prompt.hpp" />
<Unit filename="../../src/gui/dialogs/multiplayer/mp_login.cpp" />

View file

@ -829,6 +829,7 @@ set(wesnoth-main_SRC
gui/dialogs/multiplayer/mp_create_game.cpp
gui/dialogs/multiplayer/mp_create_game_set_password.cpp
gui/dialogs/multiplayer/mp_host_game_prompt.cpp
gui/dialogs/multiplayer/mp_join_game.cpp
gui/dialogs/multiplayer/mp_join_game_password_prompt.cpp
gui/dialogs/multiplayer/mp_login.cpp
gui/dialogs/multiplayer/mp_method_selection.cpp

View file

@ -404,6 +404,7 @@ wesnoth_sources = Split("""
gui/dialogs/multiplayer/mp_create_game_set_password.cpp
gui/dialogs/multiplayer/mp_create_game.cpp
gui/dialogs/multiplayer/mp_host_game_prompt.cpp
gui/dialogs/multiplayer/mp_join_game.cpp
gui/dialogs/multiplayer/mp_join_game_password_prompt.cpp
gui/dialogs/multiplayer/mp_login.cpp
gui/dialogs/multiplayer/mp_method_selection.cpp

View file

@ -25,6 +25,7 @@
#include "gui/dialogs/message.hpp"
#include "gui/dialogs/multiplayer/mp_connect.hpp"
#include "gui/dialogs/multiplayer/mp_create_game.hpp"
#include "gui/dialogs/multiplayer/mp_join_game.hpp"
#include "gui/dialogs/multiplayer/mp_login.hpp"
#include "gui/dialogs/multiplayer/mp_staging.hpp"
#include "gui/dialogs/network_transmission.hpp"
@ -405,17 +406,6 @@ static std::unique_ptr<twesnothd_connection> open_connection(CVideo& video, cons
// The functions enter_(screen)_mode are simple functions that take care of
// creating the dialogs, then, according to the dialog result, of calling other
// of those screen functions.
static config& get_scenario(config& c)
{
if(config& scenario = c.child("scenario"))
return scenario;
else if(config& snapshot = c.child("snapshot"))
return snapshot;
else
return c;
}
static void enter_wait_mode(CVideo& video, const config& game_config, saved_game& state, twesnothd_connection* wesnothd_connection,
lobby_info& li, bool observe, int current_turn = 0)
{
@ -435,131 +425,8 @@ static void enter_wait_mode(CVideo& video, const config& game_config, saved_game
{
if(preferences::new_lobby()) {
bool download_res = true;
assert(wesnothd_connection);
config level;
DBG_MP << "download_level_data()\n";
if(!true) {
// Ask for the next scenario data.
wesnothd_connection->send_data(config("load_next_scenario"));
}
bool has_scenario_and_controllers = false;
while(!has_scenario_and_controllers) {
config revc;
bool data_res = gui2::tnetwork_transmission::wesnothd_receive_dialog(
video, "download level data", revc, *wesnothd_connection);
if(!data_res) {
DBG_MP << "download_level_data bad results\n";
download_res = false;
}
mp::check_response(data_res, revc);
if(revc.child("leave_game")) {
download_res = 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(level).child("side", index)) {
side["is_local"] = controller["is_local"];
}
++index;
}
has_scenario_and_controllers = true;
}
}
std::cerr << "download_level_data() success.\n";
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(true) {
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(level)["name"].t_str());
game_config::add_color_info(get_scenario(level));
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(level).child_range("side")) {
//std::cerr << "*** 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(level).child_count("side") << " sides were unsuitable\n";
//set_result(QUIT);
return;
}
}
mp::level_to_gamestate(level, state);
campaign_info.reset(new mp_campaign_info(*wesnothd_connection));
//campaign_info->connected_players.insert(li.users().begin(), li.users().end());
ng::connect_engine_ptr connect_engine(new ng::connect_engine(state, true, campaign_info.get()));
connect_engine->receive_from_server(level);
gui2::tmp_staging dlg(*connect_engine, li, wesnothd_connection);
gui2::tmp_join_game dlg(state, li, *wesnothd_connection, true, observe);
dlg.show(video);
if(dlg.get_retval() == gui2::twindow::OK) {
@ -568,9 +435,9 @@ static void enter_wait_mode(CVideo& video, const config& game_config, saved_game
controller.play_game();
}
//if(wesnothd_connection) {
// wesnothd_connection->send_data(config("leave_game"));
//}
if(wesnothd_connection) {
wesnothd_connection->send_data(config("leave_game"));
}
return;
}

View file

@ -0,0 +1,508 @@
/*
Copyright (C) 2008 - 2016 by 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.
*/
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/dialogs/multiplayer/mp_join_game.hpp"
#include "config_assign.hpp"
#include "formula/string_utils.hpp"
#include "game_config_manager.hpp"
#include "game_initialization/mp_game_utils.hpp"
#include "game_preferences.hpp"
#include "gettext.hpp"
#include "gui/auxiliary/field.hpp"
#include "gui/dialogs/helper.hpp"
#include "gui/dialogs/message.hpp"
#include "gui/dialogs/multiplayer/faction_select.hpp"
#include "gui/dialogs/network_transmission.hpp"
#include "gui/dialogs/transient_message.hpp"
#include "gui/widgets/integer_selector.hpp"
#include "gui/widgets/button.hpp"
#include "gui/widgets/chatbox.hpp"
#include "gui/widgets/menu_button.hpp"
#include "gui/widgets/image.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "gui/widgets/list.hpp"
#else
#include "gui/widgets/listbox.hpp"
#endif
#include "gui/widgets/minimap.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/label.hpp"
#include "gui/widgets/slider.hpp"
#include "gui/widgets/stacked_widget.hpp"
#include "gui/widgets/status_label_helper.hpp"
#include "gui/widgets/toggle_button.hpp"
#include "gui/widgets/toggle_panel.hpp"
#include "gui/widgets/text_box.hpp"
#include "game_config.hpp"
#include "mp_ui_alerts.hpp"
#include "settings.hpp"
#include "statistics.hpp"
#include "units/types.hpp"
#include "formatter.hpp"
#include "wesnothd_connection.hpp"
#ifdef GUI2_EXPERIMENTAL_LISTBOX
#include "utils/functional.hpp"
#endif
namespace gui2
{
REGISTER_DIALOG(mp_join_game)
tmp_join_game::tmp_join_game(saved_game& state, lobby_info& lobby_info, twesnothd_connection& wesnothd_connection, const bool first_scenario, const bool observe_game)
: level_()
, state_(state)
, lobby_info_(lobby_info)
, wesnothd_connection_(wesnothd_connection)
, update_timer_(0)
, first_scenario_(first_scenario)
, observe_game_(observe_game)
, stop_updates_(false)
{
set_show_even_without_video(true);
}
tmp_join_game::~tmp_join_game()
{
if(update_timer_ != 0) {
remove_timer(update_timer_);
update_timer_ = 0;
}
}
/*
* Fetch the selected game's config from the server and prompts an initial faction selection.
*/
void tmp_join_game::post_build(twindow& window)
{
// Ask for the next scenario data, if applicable
if(!first_scenario_) {
wesnothd_connection_.send_data(config("load_next_scenario"));
}
bool has_scenario_and_controllers = false;
while(!has_scenario_and_controllers) {
config revc;
const bool data_res = gui2::tnetwork_transmission::wesnothd_receive_dialog(
window.video(), "download level data", revc, wesnothd_connection_);
if(!data_res) {
window.set_retval(twindow::CANCEL);
}
mp::check_response(data_res, revc);
if(revc.child("leave_game")) {
window.set_retval(twindow::CANCEL);
} 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;
}
}
if(level_["started"].to_bool()) {
window.set_retval(twindow::OK);
}
if(first_scenario_) {
state_ = saved_game();
state_.classification() = game_classification(level_);
// Make sure that we have the same config as host, if possible.
game_config_manager::get()->load_game_config_for_game(state_.classification());
}
game_config::add_color_info(get_scenario());
// If we're just an observer, we don't need to find an appropriate side and set faction selection
if(observe_game_) {
return;
}
// 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 = 0, nb_sides = 0;
for(const config& side : get_scenario().child_range("side")) {
if(side["controller"] == "reserved" && side["current_player"] == preferences::login()) {
side_choice = &side;
side_num = nb_sides;
break;
}
if(side["controller"] == "human" && side["player_id"].empty()) {
if(!side_choice) { // Found the first empty side
side_choice = &side;
side_num = nb_sides;
}
if(side["current_player"] == preferences::login()) {
side_choice = &side;
side_num = nb_sides;
break; // Found the preferred one
}
}
if(side["player_id"] == preferences::login()) {
// We already own a side in this game
return;
}
++nb_sides;
}
if(!side_choice) {
window.set_retval(twindow::CANCEL);
}
const bool allow_choice = (*side_choice)["allow_changes"].to_bool(true);
// If the client is allowed to choose their team, do that here instead of having it set by the server
if(allow_choice) {
events::event_context context;
const config& era = level_.child("era");
// TODO: Check whether we have the era. If we don't, inform the player
if(!era) {
throw config::error(_("No era information found."));
}
config::const_child_itors possible_sides = era.child_range("multiplayer_side");
if(possible_sides.empty()) {
// TODO: is this set_retval needed?
window.set_retval(twindow::CANCEL);
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);
// FIXME: this dialog doesn't show!
gui2::tfaction_select dlg(flg, color, side_num);
dlg.show(window.video());
if(dlg.get_retval() != gui2::twindow::OK) {
window.set_retval(twindow::CANCEL);
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();
wesnothd_connection_.send_data(faction);
}
}
static std::string generate_user_description(const config& side)
{
// Allow the host to override, since only the host knows the ai_algorithm.
if(const config::attribute_value* desc = side.get("user_description")) {
return desc->str();
}
const std::string controller_type = side["controller"].str();
const std::string reservation = side["reserved_for"].str();
const 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") {
return vgettext("Reserved for $playername", {{"playername", reservation}});
} else if(owner.empty()) {
return _("Vacant slot");
} else if(controller_type == "human" || controller_type == "network") {
return owner;
} else {
return _("empty");
}
}
void tmp_join_game::pre_show(twindow& window)
{
window.set_enter_disabled(true);
//
// Set title
//
tlabel& title = find_widget<tlabel>(&window, "title", false);
title.set_label((formatter() << title.label() << " " << utils::unicode_em_dash << " " << get_scenario()["name"].t_str()).str());
//
// Set up sides list
//
generate_side_list(window);
//
// Initialize chatbox and game rooms
//
tchatbox& chat = find_widget<tchatbox>(&window, "chat", false);
chat.set_lobby_info(lobby_info_);
chat.set_wesnothd_connection(wesnothd_connection_);
chat.room_window_open("this game", true); // TODO: better title?
chat.active_window_changed();
//
// Set up player list
//
update_player_list(window);
//
// Set up the network handling
//
update_timer_ = add_timer(game_config::lobby_network_timer, std::bind(&tmp_join_game::network_handler, this, std::ref(window)), true);
//
// Set up the Lua plugin context
//
plugins_context_.reset(new plugins_context("Multiplayer Join Game"));
plugins_context_->set_callback("launch", [&window](const config&) { window.set_retval(twindow::OK); }, false);
plugins_context_->set_callback("quit", [&window](const config&) { window.set_retval(twindow::CANCEL); }, false);
plugins_context_->set_callback("chat", [&chat](const config& cfg) { chat.send_chat_message(cfg["message"], false); }, true);
// TODO: the old mp wait dialog didn't have an OK button. Evaluate if we want to add one. Hiding it for now
find_widget<tbutton>(&window, "ok", false).set_visible(twidget::tvisible::hidden);
}
/*
* We don't need the full widget setup as is done initially, just value setters.
*/
void tmp_join_game::generate_side_list(twindow& window)
{
if(stop_updates_) {
return;
}
tlistbox& list = find_widget<tlistbox>(&window, "side_list", false);
window.keyboard_capture(&list);
list.clear();
for(const auto& side : get_scenario().child_range("side")) {
if(!side["allow_player"].to_bool(true)) {
continue;
}
std::map<std::string, string_map> data;
string_map item;
item["label"] = side["side"];
data.emplace("side_number", item);
std::string leader_image = ng::random_enemy_picture;
std::string leader_type = side["type"];
std::string leader_name;
const std::string leader_gender = side["gender"];
// 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 : side.child_range("unit")) {
if(side_unit["canrecruit"].to_bool()) {
leader_type = side_unit["type"].str();
break;
}
}
if(const unit_type* ut = unit_types.find(leader_type)) {
const unit_type& type = ut->get_gender_unit_type(leader_gender);
const std::string color = !side["color"].empty() ? side["color"] : side["side"].str();
leader_image = formatter() << type.image() << "~RC(" << type.flag_rgb() << ">" << color << ")";
leader_name = type.type_name();
}
item["label"] = leader_image;
data.emplace("leader_image", item);
std::string description = generate_user_description(side);
if(!leader_name.empty()) {
description += formatter() << " (<i>" << leader_name << "</i>)";
}
item["label"] = description;
data.emplace("leader_type", item);
item["label"] = (formatter() << "<span color='#a69275'>" << side["faction_name"] << "</span>").str();
data.emplace("leader_faction", item);
std::string gender_icon = "icons/icon-random.png";
if(side["gender"] != "null") {
gender_icon = formatter() << "icons/icon-" << leader_gender << ".png";
}
item["label"] = gender_icon;
item["tooltip"] = side["gender"];
data.emplace("leader_gender", item);
item.clear();
// TODO: why this tstring stuff?
item["label"] = t_string::from_serialized(side["user_team_name"].str());
data.emplace("side_team", item);
// Don't show gold for saved games
// TODO: gold icon
if(side["allow_changes"].to_bool()) {
item["label"] = side["gold"].str() + " " + "Gold";
data.emplace("side_gold", item);
}
const int income_amt = side["income"];
if(income_amt != 0) {
const std::string income_string = formatter() << (income_amt > 0 ? "+" : "") << income_amt << "Income";
item["label"] = income_string;
data.emplace("side_income", item);
}
// TODO: colorize
item["label"] = side["color"];
data.emplace("side_color", item);
list.add_row(data);
}
}
void tmp_join_game::update_player_list(twindow& window)
{
tlistbox& player_list = find_widget<tlistbox>(&window, "player_list", false);
player_list.clear();
for(const auto& side : get_scenario().child_range("side")) {
std::map<std::string, string_map> data;
string_map item;
item["label"] = side["player_id"];
data.emplace("player_name", item);
player_list.add_row(data);
}
}
void tmp_join_game::network_handler(twindow& window)
{
config data;
if(!wesnothd_connection_.receive_data(data)) {
return;
}
// Update chat
find_widget<tchatbox>(&window, "chat", false).process_network_data(data);
if(!data["message"].empty()) {
gui2::show_transient_message(window.video(), _("Response") , data["message"]);
}
if(data["failed"].to_bool()) {
window.set_retval(twindow::CANCEL);
} else if(data.child("start_game")) {
window.set_retval(twindow::OK);
} else if(data.child("leave_game")) {
window.set_retval(twindow::CANCEL);
}
if(data.child("stop_updates")) {
stop_updates_ = true;
} else if(const config& c = data.child("scenario_diff")) {
// TODO: We should catch config::error and then leave the game.
level_.apply_diff(c);
generate_side_list(window);
} else if(const config& change = data.child("change_controller")) {
if(config& side_to_change = get_scenario().find_child("side", "side", change["side"])) {
side_to_change.merge_with(change);
}
} else if(data.has_child("scenario") || data.has_child("snapshot") || data.child("next_scenario")) {
level_ = first_scenario_ ? data : data.child("next_scenario");
generate_side_list(window);
}
// Update player list
// TODO: optimally, it wouldn't regenerate the entire list every single refresh cycle
update_player_list(window);
}
config& tmp_join_game::get_scenario()
{
if(config& scenario = level_.child("scenario")) {
return scenario;
} else if(config& snapshot = level_.child("snapshot")) {
return snapshot;
}
return level_;
}
void tmp_join_game::post_show(twindow& window)
{
if(window.get_retval() == twindow::OK) {
if(const config& stats = level_.child("statistics")) {
statistics::fresh_stats();
statistics::read_stats(stats);
}
mp::level_to_gamestate(level_, state_);
mp_ui_alerts::game_has_begun();
} else {
wesnothd_connection_.send_data(config("leave_game"));
}
}
} // namespace gui2

View file

@ -0,0 +1,87 @@
/*
Copyright (C) 2008 - 2016 by 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 GUI_DIALOGS_MP_JOIN_GAME_HPP_INCLUDED
#define GUI_DIALOGS_MP_JOIN_GAME_HPP_INCLUDED
#include "ai/configuration.hpp"
#include "gui/dialogs/dialog.hpp"
#include "gui/dialogs/lobby/info.hpp"
#include "gui/dialogs/multiplayer/plugin_executor.hpp"
#include "game_initialization/connect_engine.hpp"
#include "game_initialization/multiplayer.hpp"
#include "mp_game_settings.hpp"
class config;
namespace gui2
{
class ttoggle_button;
class ttoggle_panel;
class tslider;
class tlabel;
class tmenu_button;
class twidget;
class tmp_join_game : public tdialog, private plugin_executor
{
public:
tmp_join_game(saved_game& state, lobby_info& lobby_info, twesnothd_connection& wesnothd_connection,
const bool first_scenario = true, const bool observe_game = false);
~tmp_join_game();
private:
/** Inherited from tdialog, implemented by REGISTER_DIALOG. */
virtual const std::string& window_id() const;
/** Inherited from tdialog. */
void post_build(twindow& window);
/** Inherited from tdialog. */
void pre_show(twindow& window);
/** Inherited from tdialog. */
void post_show(twindow& window);
void generate_side_list(twindow& window);
void update_player_list(twindow& window);
void update_leader_display(ng::side_engine& side, tgrid& row_grid);
void network_handler(twindow& window);
config& get_scenario();
config level_;
saved_game& state_;
lobby_info& lobby_info_;
twesnothd_connection& wesnothd_connection_;
size_t update_timer_;
const bool first_scenario_;
const bool observe_game_;
bool stop_updates_;
};
} // namespace gui2
#endif

View file

@ -468,8 +468,7 @@ void tmp_staging::post_show(twindow& window)
{
if(window.get_retval() == twindow::OK) {
connect_engine_.start_game();
}
else {
} else {
connect_engine_.leave_game();
}
}

View file

@ -75,6 +75,7 @@
#include "gui/dialogs/multiplayer/mp_connect.hpp"
#include "gui/dialogs/multiplayer/mp_create_game.hpp"
#include "gui/dialogs/multiplayer/mp_create_game_set_password.hpp"
#include "gui/dialogs/multiplayer/mp_join_game.hpp"
#include "gui/dialogs/multiplayer/mp_join_game_password_prompt.hpp"
#include "gui/dialogs/multiplayer/mp_staging.hpp"
#include "gui/dialogs/depcheck_confirm_change.hpp"
@ -410,6 +411,7 @@ BOOST_AUTO_TEST_CASE(test_gui2)
test<gui2::tmp_connect>();
//test<gui2::tmp_create_game>();
test<gui2::tmp_create_game_set_password>();
test<gui2::tmp_join_game>();
test<gui2::tmp_join_game_password_prompt>();
test<gui2::tdepcheck_confirm_change>();
test<gui2::tdepcheck_select_new>();
@ -486,6 +488,7 @@ BOOST_AUTO_TEST_CASE(test_gui2)
"title_screen",
"end_credits",
"mp_staging",
"mp_join_game",
};
std::sort(list.begin(), list.end());
std::sort(omitted.begin(), omitted.end());