← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/game_end_summary into lp:widelands

 

cghislai has proposed merging lp:~widelands-dev/widelands/game_end_summary into lp:widelands.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #576347 in widelands: "show game results screen"
  https://bugs.launchpad.net/widelands/+bug/576347

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/game_end_summary/+merge/176000

So I have the game end screen prototypes and I need feedbacl. I am not sure if I must go for an ingame window or a fullscreen menu screen. If you test this branch, you will first see the ingame window, then if you click on Quit you will be warried to the fullscreen window.

To help you test, there is a Test Win win condition that will make the player 1 win after 15s - so make sure someone is occupying the 1st slot.
The layout and table sorting are not finished yet, but please voice your concerns.
-- 
https://code.launchpad.net/~widelands-dev/widelands/game_end_summary/+merge/176000
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/game_end_summary into lp:widelands.
=== modified file 'scripting/win_condition_functions.lua'
--- scripting/win_condition_functions.lua	2012-04-25 07:29:45 +0000
+++ scripting/win_condition_functions.lua	2013-07-24 11:22:30 +0000
@@ -115,3 +115,11 @@
        wl.game.report_result(p, true, 0, make_extra_data(p, wc_name, wc_ver))
    end
 end
+
+function broadcast_lost(plrs, header, msg, goptions, wc_name, wc_ver)
+   local options = goptions or {}
+   for idx, p in ipairs(plrs) do
+       p:send_message(header, msg, options)
+       wl.game.report_result(p, false, 0, make_extra_data(p, wc_name, wc_ver))
+   end
+end

=== modified file 'scripting/win_conditions/01_defeat_all.lua'
--- scripting/win_conditions/01_defeat_all.lua	2012-02-27 20:38:01 +0000
+++ scripting/win_conditions/01_defeat_all.lua	2013-07-24 11:22:30 +0000
@@ -30,8 +30,7 @@
 		-- Send congratulations to all remaining players
 		broadcast_win(plrs,
 				won_game.title,
-				won_game.body,
-				{popup = true},
+				won_game.body,{},
 				wc_name, wc_version
 		)
 

=== added file 'scripting/win_conditions/02_test.lua'
--- scripting/win_conditions/02_test.lua	1970-01-01 00:00:00 +0000
+++ scripting/win_conditions/02_test.lua	2013-07-24 11:22:30 +0000
@@ -0,0 +1,33 @@
+-- =======================================================================
+--                         Defeat all Win condition
+-- =======================================================================
+
+use("aux", "coroutine") -- for sleep
+use("aux", "win_condition_functions")
+
+set_textdomain("win_conditions")
+
+use("aux", "win_condition_texts")
+
+local wc_name = _ "Test Win"
+local wc_version = 2
+local wc_desc = _ "The tribe or team that can defeat all others wins the game!"
+return {
+	name = wc_name,
+	description = wc_desc,
+	func = function()
+		local plrs = wl.Game().players
+
+		broadcast(plrs, wc_name, wc_desc)
+		sleep(15000)
+		wl.game.report_result(plrs[1], true, 0, make_extra_data(plrs[1], wc_name, wc_version))
+		table.remove(plrs, 1)
+
+		broadcast_lost(plrs,
+				wc_name,
+				"Bravo!",
+				{}, wc_name, wc_version
+		)
+
+	end,
+}

=== modified file 'scripting/win_conditions/03_territorial_lord.lua'
--- scripting/win_conditions/03_territorial_lord.lua	2013-06-08 10:48:35 +0000
+++ scripting/win_conditions/03_territorial_lord.lua	2013-07-24 11:22:30 +0000
@@ -162,9 +162,9 @@
 			for idx, p in ipairs(plrs) do
 				if candidateisteam and currentcandidate == p.team
 					or not candidateisteam and currentcandidate == p.name then
-					p:send_message(game_status.title, msg2, {popup = true})
+					p:send_message(game_status.title, msg2)
 				else
-					p:send_message(game_status.title, msg1, {popup = true})
+					p:send_message(game_status.title, msg1)
 				end
 			end
 		end
@@ -189,10 +189,10 @@
 					p.see_all = 1
 					if candidateisteam and currentcandidate == p.team
 						or not candidateisteam and currentcandidate == p.name then
-						p:send_message(won_game_over.title, won_game_over.body, {popup = true})
+						p:send_message(won_game_over.title, won_game_over.body)
 						wl.game.report_result(p, true, _landsizes[p.number], make_extra_data(p, wc_name, wc_version))
 					else
-						p:send_message(lost_game_over.title, lost_game_over.body, {popup = true})
+						p:send_message(lost_game_over.title, lost_game_over.body)
 						wl.game.report_result(p, false, _landsizes[p.number], make_extra_data(p, wc_name, wc_version))
 					end
 				end

=== modified file 'scripting/win_conditions/03_territorial_time.lua'
--- scripting/win_conditions/03_territorial_time.lua	2013-07-18 14:36:20 +0000
+++ scripting/win_conditions/03_territorial_time.lua	2013-07-24 11:22:30 +0000
@@ -258,10 +258,10 @@
 			for i=1,#points do
 				if points[i][1] == game_status_territoral_lord.team:format(p.team) or points[i][1] == p.name then
 					if points[i][2] >= maxpoints then
-						p:send_message(won_game_over.title, wonmsg .. _status(points, "had"), {popup = true})
+						p:send_message(won_game_over.title, wonmsg .. _status(points, "had"))
 						wl.game.report_result(p, true, _landsizes[p.number], make_extra_data(p, wc_name, wc_version))
 					else
-						p:send_message(lost_game_over.title, lostmsg .. _status(points, "had"), {popup = true})
+						p:send_message(lost_game_over.title, lostmsg .. _status(points, "had"))
 						wl.game.report_result(p, false, _landsizes[p.number], make_extra_data(p, wc_name, wc_version))
 					end
 				end

=== modified file 'scripting/win_conditions/04_wood_gnome.lua'
--- scripting/win_conditions/04_wood_gnome.lua	2012-02-27 20:38:01 +0000
+++ scripting/win_conditions/04_wood_gnome.lua	2013-07-24 11:22:30 +0000
@@ -144,12 +144,12 @@
 	for i=1,#points-1 do
 		privmsg = lost_game_over.title
 		privmsg = privmsg .. msg
-		points[i][1]:send_message(lost_game_over.body, privmsg, {popup = true})
+		points[i][1]:send_message(lost_game_over.body, privmsg)
 		wl.game.report_result(points[i][1], false, points[i][2], make_extra_data(points[i][1], wc_name, wc_version))
 	end
 	privmsg = won_game_over.title
 	privmsg = privmsg .. msg
-	points[#points][1]:send_message(won_game_over.body, privmsg, {popup = true})
+	points[#points][1]:send_message(won_game_over.body, privmsg)
 	wl.game.report_result(points[#points][1], true, points[#points][2], make_extra_data(points[#points][1], wc_name, wc_version))
 end
 }

=== modified file 'src/gamecontroller.cc'
--- src/gamecontroller.cc	2013-07-18 05:40:10 +0000
+++ src/gamecontroller.cc	2013-07-24 11:22:30 +0000
@@ -43,6 +43,7 @@
 	void setDesiredSpeed(uint32_t speed);
 	bool isPaused();
 	void setPaused(bool paused);
+	void report_result(uint8_t player, int32_t score, bool win, std::string extra);
 
 	// Chat provider implementation
 	void send(const std::string & msg);
@@ -163,6 +164,20 @@
 	m_paused = paused;
 }
 
+void SinglePlayerGameController::report_result(uint8_t p_nr, int32_t score, bool win, std::string extra)
+{
+	Widelands::PlayerEndStatus pes;
+	Widelands::Player* player = m_game.get_player(p_nr);
+	assert(player);
+	pes.player = player->player_number();
+	pes.time = m_game.get_gametime();
+	pes.points = score;
+	pes.win = win;
+	pes.lost = !win;
+	pes.extra = extra;
+	m_game.add_player_end_status(pes);
+}
+
 void SinglePlayerGameController::send_local(const std::string& msg)
 {
 	ChatMessage c;

=== modified file 'src/logic/editor_game_base.cc'
--- src/logic/editor_game_base.cc	2013-07-23 14:49:48 +0000
+++ src/logic/editor_game_base.cc	2013-07-24 11:22:30 +0000
@@ -302,7 +302,7 @@
 {
 	Player & plr = player(owner);
 	const Tribe_Descr & tribe = plr.tribe();
-	return 
+	return
 		tribe.get_building_descr(idx)->create
 			(*this, plr, c, false, true, former_buildings);
 }

=== modified file 'src/logic/game.cc'
--- src/logic/game.cc	2013-07-21 09:42:23 +0000
+++ src/logic/game.cc	2013-07-24 11:22:30 +0000
@@ -54,6 +54,7 @@
 #include "wlapplication.h"
 #include "wui/game_tips.h"
 #include "wui/interactive_player.h"
+#include "wui/game_summary.h"
 #include "militarysite.h"
 
 #include <cstring>
@@ -168,13 +169,21 @@
 /**
  * \return a pointer to the \ref Interactive_Player if any.
  * \note This function may return 0 (in particular, it will return 0 during
- * playback)
+ * playback or if player is spectator)
  */
 Interactive_Player * Game::get_ipl()
 {
 	return dynamic_cast<Interactive_Player *>(get_ibase());
 }
 
+/**
+ * \return a pointer to the \ref Interactive_GameBase if any.
+ * \note This function may return 0.
+ */
+Interactive_GameBase * Game::get_igbase()
+{
+	return dynamic_cast<Interactive_GameBase *>(get_ibase());
+}
 
 void Game::set_game_controller(GameController * const ctrl)
 {
@@ -323,7 +332,6 @@
 			 playersettings.name,
 			 playersettings.team);
 		get_player(i + 1)->setAI(playersettings.ai);
-		m_number_of_players++;
 	}
 
 	// Add shared in starting positions
@@ -422,7 +430,10 @@
 	}
 	if (m_number_of_players == 0) {
 		// Old savegame loaded, parse players to figure out their amount
-		iterate_players_existing_const(p, map().get_nrplayers(), *this, player_tmp) {
+		iterate_players_existing(p, map().get_nrplayers(), *this, pl) {
+			if (pl->player_number() > UserSettings::highestPlayernum()) {
+				continue;
+			}
 			m_number_of_players++;
 		}
 	}
@@ -498,11 +509,11 @@
 					loader_ui->step(step_description);
 				}
 				plr->create_default_infrastructure();
-
+				m_number_of_players++;
 			}
-		} else
+		} else {
 			// Is a scenario!
-			iterate_players_existing_novar(p, nr_players, *this)
+			iterate_players_existing_novar(p, nr_players, *this) {
 				if (not map().get_starting_pos(p))
 				throw warning
 					(_("Missing starting position"),
@@ -512,6 +523,9 @@
 					 	 "You can manually add a starting position with Widelands "
 					 	 "Editor, to fix this problem."),
 					 p);
+				m_number_of_players++;
+			}
+		}
 
 		if (get_ipl())
 			get_ipl()->move_view_to
@@ -1167,4 +1181,30 @@
 		}
 }
 
+/**
+ * Adds a new player status for a player that left the game.
+ */
+void Game::add_player_end_status(const PlayerEndStatus status)
+{
+	// Ensure we don't have a status for it yet
+	std::vector<PlayerEndStatus>::iterator it;
+	for (it = m_players_end_status.begin(); it != m_players_end_status.end(); ++it) {
+		PlayerEndStatus pes = *it;
+		if (pes.player == status.player) {
+			log("End status for player %i already registered\n", pes.player);
+			assert(false);
+		}
+	}
+	m_players_end_status.push_back(status);
+
+	// If all results have been gathered, save game ans show summary screen
+	if (m_players_end_status.size() < m_number_of_players) {
+		return;
+	}
+
+	if (get_igbase()) {
+		get_igbase()->show_game_summary();
+	}
+}
+
 }

=== modified file 'src/logic/game.h'
--- src/logic/game.h	2013-07-20 09:56:51 +0000
+++ src/logic/game.h	2013-07-24 11:22:30 +0000
@@ -40,6 +40,7 @@
 struct Path;
 struct PlayerImmovable;
 struct Ship;
+struct PlayerEndStatus;
 class TrainingSite;
 class MilitarySite;
 
@@ -172,6 +173,7 @@
 	void send_player_ship_explore_island(Ship &, bool);
 
 	Interactive_Player * get_ipl();
+	Interactive_GameBase * get_igbase();
 
 	SaveHandler & save_handler() {return m_savehandler;}
 
@@ -189,6 +191,9 @@
 	// Returns the number of players (human or ai) occupying a slot.
 	uint8_t get_number_of_players() {return m_number_of_players;}
 
+	const std::vector<PlayerEndStatus> & get_players_end_status() {return m_players_end_status;}
+	void add_player_end_status(PlayerEndStatus status);
+
 private:
 	void SyncReset();
 
@@ -254,6 +259,8 @@
 	/// For save games and statistics generation
 	std::string          m_win_condition_displayname;
 	uint8_t              m_number_of_players;
+
+	std::vector<PlayerEndStatus> m_players_end_status;
 };
 
 inline Coords Game::random_location(Coords location, uint8_t radius) {

=== modified file 'src/logic/player.h'
--- src/logic/player.h	2013-07-08 03:35:09 +0000
+++ src/logic/player.h	2013-07-24 11:22:30 +0000
@@ -45,6 +45,18 @@
 struct AttackController;
 
 /**
+ * Hold data once a player left the game, or on game ends.
+ */
+struct PlayerEndStatus {
+	Player_Number player;
+	bool win;
+	bool lost;
+	uint32_t time;
+	uint32_t points;
+	std::string extra;
+};
+
+/**
  * Manage in-game aspects of players, such as tribe, team, fog-of-war, statistics,
  * messages (notification when a resource has been found etc.) and so on.
  *

=== modified file 'src/network/netclient.cc'
--- src/network/netclient.cc	2013-07-23 18:09:24 +0000
+++ src/network/netclient.cc	2013-07-24 11:22:30 +0000
@@ -29,6 +29,7 @@
 #include "io/fileread.h"
 #include "io/filewrite.h"
 #include "logic/game.h"
+#include "logic/player.h"
 #include "logic/playercommand.h"
 #include "map_io/widelands_map_loader.h"
 #include "network_gaming_messages.h"
@@ -299,6 +300,22 @@
 	return buf;
 }
 
+void NetClient::report_result(uint8_t player_nr, int32_t points, bool win, std::string extra)
+{
+	// Send to game
+	Widelands::PlayerEndStatus pes;
+	Widelands::Player* player = d->game->get_player(player_nr);
+	assert(player);
+	pes.player = player->player_number();
+	pes.time = d->game->get_gametime();
+	pes.points = points;
+	pes.win = win;
+	pes.lost = !win;
+	pes.extra = extra;
+	d->game->add_player_end_status(pes);
+}
+
+
 const GameSettings & NetClient::settings()
 {
 	return d->settings;

=== modified file 'src/network/netclient.h'
--- src/network/netclient.h	2013-07-16 13:26:14 +0000
+++ src/network/netclient.h	2013-07-24 11:22:30 +0000
@@ -56,6 +56,7 @@
 	void setDesiredSpeed(uint32_t speed);
 	bool isPaused();
 	void setPaused(bool paused);
+	void report_result(uint8_t player, int32_t points, bool win, std::string extra);
 	// End GameController interface
 
 	// GameSettingsProvider interface

=== modified file 'src/network/nethost.cc'
--- src/network/nethost.cc	2013-07-21 08:07:18 +0000
+++ src/network/nethost.cc	2013-07-24 11:22:30 +0000
@@ -501,7 +501,7 @@
 		ChatMessage c;
 		c.time = time(0);
 		c.msg = msg;
-		ChatProvider::send(c);
+		receive(c);
 	}
 
 	const std::vector<ChatMessage> & getMessages() const {
@@ -2978,13 +2978,25 @@
 }
 
 
-void NetHost::report_result(uint8_t player, int32_t points, bool win, std::string extra)
+void NetHost::report_result(uint8_t p_nr, int32_t points, bool win, std::string extra)
 {
+	// Send to game
+	Widelands::PlayerEndStatus pes;
+	Widelands::Player* player = d->game->get_player(p_nr);
+	assert(player);
+	pes.player = player->player_number();
+	pes.time = d->game->get_gametime();
+	pes.points = points;
+	pes.win = win;
+	pes.lost = !win;
+	pes.extra = extra;
+	d->game->add_player_end_status(pes);
+
 	// there might be more than one client that control this Widelands player
 	// and maybe even none -> computer player
 	for (uint16_t i = 0; i < d->settings.users.size(); ++i) {
 		UserSettings & user = d->settings.users.at(i);
-		if (user.position == player - 1) {
+		if (user.position == p_nr - 1) {
 			user.winner               = win;
 			user.points               = points;
 			user.win_condition_string = extra;

=== modified file 'src/save_handler.cc'
--- src/save_handler.cc	2013-07-21 08:07:18 +0000
+++ src/save_handler.cc	2013-07-24 11:22:30 +0000
@@ -69,8 +69,10 @@
 
 	// TODO: defer saving to next tick so that this message is shown
 	// before the actual save, or put the saving logic in another thread
-	game.get_ipl()->get_chat_provider()->send_local
-		(_("Saving game..."));
+	if (game.get_igbase()) {
+		game.get_igbase()->get_chat_provider()->send_local
+			(_("Saving game..."));
+	}
 
 	// save the game
 	const std::string complete_filename = create_file_name(get_base_dir(), filename);
@@ -109,8 +111,10 @@
 	}
 
 	log("Autosave: save took %d ms\n", m_last_saved_time - realtime);
-	game.get_ipl()->get_chat_provider()->send_local
-		(_("Game saved"));
+	if (game.get_igbase()) {
+		game.get_igbase()->get_chat_provider()->send_local
+			(_("Game saved"));
+	}
 }
 
 /**

=== modified file 'src/ui_fsmenu/main.h'
--- src/ui_fsmenu/main.h	2012-02-15 21:25:34 +0000
+++ src/ui_fsmenu/main.h	2013-07-24 11:22:30 +0000
@@ -32,6 +32,7 @@
 struct Fullscreen_Menu_Main : public Fullscreen_Menu_Base {
 	Fullscreen_Menu_Main();
 	enum {
+		mm_summary,
 		mm_playtutorial,
 		mm_singleplayer,
 		mm_multiplayer,

=== added file 'src/wui/game_summary.cc'
--- src/wui/game_summary.cc	1970-01-01 00:00:00 +0000
+++ src/wui/game_summary.cc	2013-07-24 11:22:30 +0000
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2007-2008 by the Widelands Development Team
+ *
+ * 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; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#include "game_summary.h"
+
+#include "interactive_gamebase.h"
+#include "interactive_player.h"
+#include "ui_basic/unique_window.h"
+#include "ui_basic/box.h"
+#include "ui_basic/textarea.h"
+#include "ui_basic/table.h"
+#include "ui_basic/button.h"
+#include "graphic/graphic.h"
+#include "logic/game.h"
+#include "logic/player.h"
+#include "wlapplication.h"
+#include "timestring.h"
+
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+
+#define PADDING 4
+
+GameSummaryScreen::GameSummaryScreen
+	(Interactive_GameBase * parent, UI::UniqueWindow::Registry * r)
+: UI::UniqueWindow(parent, "game_summary", r, 500, 400, _("Game over")),
+m_game(parent->game())
+{
+	// Init boxes
+	UI::Box * vbox = new UI::Box(this, 0, 0, UI::Box::Vertical, 0, 0, PADDING);
+	m_title_area = new UI::Textarea(vbox, "", UI::Align_HCenter);
+	vbox->add(m_title_area, UI::Box::AlignCenter);
+	vbox->add_space(PADDING);
+
+	UI::Box * hbox1 = new UI::Box(this, 0, 0, UI::Box::Horizontal);
+	m_players_table = new UI::Table<const uintptr_t>(hbox1, 0, 0, 300, 200);
+	hbox1->add_space(PADDING);
+	hbox1->add(m_players_table, UI::Box::AlignTop);
+	hbox1->add_space(PADDING);
+
+	UI::Box * infoBox = new UI::Box(hbox1, 0, 0, UI::Box::Vertical, 0, 0);
+	m_gametime_label = new UI::Textarea(infoBox, _("Gametime :"));
+	infoBox->add(m_gametime_label, UI::Box::AlignLeft);
+	m_gametime_value = new UI::Textarea(infoBox);
+	infoBox->add(m_gametime_value, UI::Box::AlignRight);
+	infoBox->add_space(PADDING);
+	hbox1->add(infoBox, UI::Box::AlignTop);
+	hbox1->add_space(PADDING);
+	vbox->add(hbox1, UI::Box::AlignLeft);
+	vbox->add_space(PADDING);
+
+	UI::Box * buttonBox = new UI::Box(this, 0, 0, UI::Box::Horizontal);
+	m_continue_button = new UI::Button
+		(buttonBox, "continue_button",
+		0, 0, 100, 32, g_gr->images().get("pics/but0.png"),
+		_("Continue"), _("Continue playing"));
+	buttonBox->add(m_continue_button, UI::Box::AlignRight);
+	buttonBox->add_space(PADDING);
+	m_stop_button = new UI::Button
+		(buttonBox, "stop_button",
+		0, 0, 100, 32, g_gr->images().get("pics/but0.png"),
+		_("Quit"), _("Return to main menu"));
+	buttonBox->add(m_stop_button, UI::Box::AlignRight);
+	vbox->add(buttonBox, UI::Box::AlignBottom);
+	vbox->add_space(PADDING);
+	set_center_panel(vbox);
+
+	// Prepare table
+	m_players_table->add_column(150, _("Player"));
+	m_players_table->add_column(50, _("Team"), UI::Align_HCenter);
+	m_players_table->add_column(100, _("Status"), UI::Align_HCenter);
+	m_players_table->add_column(100, _("Time"));
+	m_players_table->add_column(100, _("Score"), UI::Align_Right);
+
+	// Prepare Elements
+	m_title_area->set_textstyle(UI::TextStyle::ui_big());
+
+	// Connections
+	m_continue_button->sigclicked.connect
+		(boost::bind(&GameSummaryScreen::continue_clicked, this));
+	m_stop_button->sigclicked.connect
+		(boost::bind(&GameSummaryScreen::stop_clicked, this));
+	m_players_table->selected.connect
+		(boost::bind(&GameSummaryScreen::player_selection, this, _1));
+
+	// Window
+	center_to_parent();
+	set_can_focus(true);
+	focus();
+	fill_data();
+}
+
+bool GameSummaryScreen::handle_mousepress(Uint8 btn, int32_t mx, int32_t my)
+{
+	// Prevent closing with right click
+	if (btn == SDL_BUTTON_RIGHT)
+		return true;
+
+	return UI::Window::handle_mousepress(btn, mx, my);
+}
+
+void GameSummaryScreen::fill_data()
+{
+	std::vector<Widelands::PlayerEndStatus> players_status
+		= m_game.get_players_end_status();
+	bool local_in_game = false;
+	bool local_won = false;
+	Widelands::Player* single_won = NULL;
+	uint8_t team_won = 0;
+	Interactive_Player* ipl = m_game.get_ipl();
+
+	BOOST_FOREACH(Widelands::PlayerEndStatus pes, players_status) {
+		if (ipl && pes.player == ipl->player_number()) {
+			local_in_game = true;
+			local_won = pes.win;
+		}
+		Widelands::Player* p = m_game.get_player(pes.player);
+		UI::Table<uintptr_t>::Entry_Record & te
+			= m_players_table->add(pes.player);
+		// Player name & pic
+		char buf[256];
+		sprintf(buf, "pics/genstats_enable_plr_0%u.png", pes.player);
+		const Image* pic = g_gr->images().get(buf);
+		te.set_picture(0, pic, p->get_name());
+		// Team
+		sprintf(buf, "%i", p->team_number());
+		te.set_string(1, buf);
+		// Status
+		std::string stat_str = _("Resigned");
+		if (pes.lost) {
+			stat_str = _("Lost");
+		} else if (pes.win) {
+			stat_str = _("Won");
+			if (!single_won) {
+				single_won = p;
+			} else {
+				team_won = p->team_number();
+			}
+		}
+		te.set_string(2, stat_str);
+		// Time
+		te.set_string(3, gametimestring(pes.time));
+		// Points
+		sprintf(buf, "%i", pes.points);
+		te.set_string(4, buf);
+	}
+
+	if (local_in_game) {
+		if (local_won) {
+			m_title_area->set_text(_("You won!"));
+		} else {
+			m_title_area->set_text(_("You lost.."));
+		}
+	} else {
+		if (team_won <= 0) {
+			m_title_area->set_text
+				((boost::format("%s won!") % single_won->get_name()).str());
+		} else {
+			m_title_area->set_text
+				((boost::format("Team %i won!") % team_won).str());
+		}
+	}
+	m_players_table->update();
+	m_gametime_value->set_text(gametimestring(m_game.get_gametime()));
+}
+
+void GameSummaryScreen::player_selection(uint8_t idx)
+{
+
+}
+
+void GameSummaryScreen::continue_clicked()
+{
+	die();
+}
+
+void GameSummaryScreen::stop_clicked()
+{
+	m_game.get_ibase()->end_modal(0);
+}
+

=== added file 'src/wui/game_summary.h'
--- src/wui/game_summary.h	1970-01-01 00:00:00 +0000
+++ src/wui/game_summary.h	2013-07-24 11:22:30 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007-2008 by the Widelands Development Team
+ *
+ * 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; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ */
+
+#ifndef GAME_SUMMARY_H
+#define GAME_SUMMARY_H
+
+#include "ui_basic/unique_window.h"
+#include "ui_basic/box.h"
+#include "ui_basic/textarea.h"
+#include "ui_basic/table.h"
+#include "ui_basic/button.h"
+
+#include <boost/signal.hpp>
+
+class Interactive_GameBase;
+namespace Widelands
+{
+struct Game;
+}
+
+/// Shows an ingame summary window on game end
+struct GameSummaryScreen : UI::UniqueWindow {
+	GameSummaryScreen
+		(Interactive_GameBase * parent, UI::UniqueWindow::Registry * r);
+
+	bool handle_mousepress(Uint8 btn, int32_t mx, int32_t my);
+private:
+	void fill_data();
+	void player_selection(uint8_t idx);
+	void stop_clicked();
+	void continue_clicked();
+
+	Widelands::Game & m_game;
+	UI::Textarea *  m_title_area;
+	UI::Textarea *  m_gametime_label;
+	UI::Textarea *  m_gametime_value;
+	UI::Button *    m_continue_button;
+	UI::Button *    m_stop_button;
+	UI::Table<uintptr_t const> *     m_players_table;
+};
+
+#endif

=== modified file 'src/wui/interactive_gamebase.cc'
--- src/wui/interactive_gamebase.cc	2012-12-17 20:01:04 +0000
+++ src/wui/interactive_gamebase.cc	2013-07-24 11:22:30 +0000
@@ -19,6 +19,7 @@
 
 #include "interactive_gamebase.h"
 
+#include "game_summary.h"
 #include "chatoverlay.h"
 #include "profile/profile.h"
 #include "upcast.h"
@@ -97,3 +98,14 @@
 
 	return false;
 }
+
+void Interactive_GameBase::show_game_summary()
+{
+	if (m_game_summary.window) {
+		m_game_summary.window->set_visible(true);
+		m_game_summary.window->think();
+		return;
+	}
+	GameSummaryScreen* gsc = new GameSummaryScreen(this, &m_game_summary);
+}
+

=== modified file 'src/wui/interactive_gamebase.h'
--- src/wui/interactive_gamebase.h	2013-02-10 19:36:24 +0000
+++ src/wui/interactive_gamebase.h	2013-07-24 11:22:30 +0000
@@ -79,6 +79,8 @@
 
 	bool try_show_ship_window();
 
+	void show_game_summary();
+
 protected:
 	Game_Main_Menu_Windows m_mainm_windows;
 	ChatProvider           * m_chatProvider;
@@ -90,6 +92,7 @@
 
 	PlayerType m_playertype;
 	UI::UniqueWindow::Registry m_fieldaction;
+	UI::UniqueWindow::Registry m_game_summary;
 };
 
 #endif


References