← Back to team overview

widelands-dev team mailing list archive

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

 

GunChleoc has proposed merging lp:~widelands-dev/widelands/wincondition_dropdown_multiplayer into lp:widelands.

Commit message:
Multiplayer win condition is now also selected by a dropdown. Fixed crashes with joining Artifacts games.

Requested reviews:
  Widelands Developers (widelands-dev)
Related bugs:
  Bug #1645842 in widelands: "Segfault in launch_mpg.cc while trying to join an internet game"
  https://bugs.launchpad.net/widelands/+bug/1645842

For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/wincondition_dropdown_multiplayer/+merge/322196
-- 
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/wincondition_dropdown_multiplayer into lp:widelands.
=== modified file 'src/logic/game_settings.h'
--- src/logic/game_settings.h	2017-01-25 18:55:59 +0000
+++ src/logic/game_settings.h	2017-04-07 12:02:48 +0000
@@ -161,8 +161,7 @@
 	virtual void set_player_team(uint8_t number, Widelands::TeamNumber team) = 0;
 	virtual void set_player_closeable(uint8_t number, bool closeable) = 0;
 	virtual void set_player_shared(uint8_t number, uint8_t shared) = 0;
-	virtual void set_win_condition_script(std::string wc) = 0;
-	virtual void next_win_condition() = 0;
+	virtual void set_win_condition_script(const std::string& wc) = 0;
 	virtual std::string get_win_condition_script() = 0;
 
 	struct NoTribe {};

=== modified file 'src/logic/single_player_game_settings_provider.cc'
--- src/logic/single_player_game_settings_provider.cc	2017-01-30 14:40:12 +0000
+++ src/logic/single_player_game_settings_provider.cc	2017-04-07 12:02:48 +0000
@@ -231,11 +231,6 @@
 	return s.win_condition_script;
 }
 
-void SinglePlayerGameSettingsProvider::set_win_condition_script(std::string wc) {
+void SinglePlayerGameSettingsProvider::set_win_condition_script(const std::string& wc) {
 	s.win_condition_script = wc;
 }
-
-void SinglePlayerGameSettingsProvider::next_win_condition() {
-	// not implemented - feel free to do so, if you need it.
-	NEVER_HERE();
-}

=== modified file 'src/logic/single_player_game_settings_provider.h'
--- src/logic/single_player_game_settings_provider.h	2017-01-25 18:55:59 +0000
+++ src/logic/single_player_game_settings_provider.h	2017-04-07 12:02:48 +0000
@@ -60,8 +60,7 @@
 	void set_player_number(uint8_t const number) override;
 
 	std::string get_win_condition_script() override;
-	void set_win_condition_script(std::string wc) override;
-	void next_win_condition() override;
+	void set_win_condition_script(const std::string& wc) override;
 
 private:
 	GameSettings s;

=== modified file 'src/network/netclient.cc'
--- src/network/netclient.cc	2017-01-30 14:40:12 +0000
+++ src/network/netclient.cc	2017-04-07 12:02:48 +0000
@@ -397,12 +397,9 @@
 	return d->settings.win_condition_script;
 }
 
-void NetClient::set_win_condition_script(std::string) {
-	// Clients are not allowed to change this
-}
-
-void NetClient::next_win_condition() {
-	// Clients are not allowed to change this
+void NetClient::set_win_condition_script(const std::string&) {
+	// Clients are not allowed to change this
+	NEVER_HERE();
 }
 
 void NetClient::set_player_number(uint8_t const number) {

=== modified file 'src/network/netclient.h'
--- src/network/netclient.h	2017-01-25 18:55:59 +0000
+++ src/network/netclient.h	2017-04-07 12:02:48 +0000
@@ -90,8 +90,7 @@
 	void set_player_team(uint8_t number, Widelands::TeamNumber team) override;
 	void set_player_closeable(uint8_t number, bool closeable) override;
 	void set_player_shared(uint8_t number, uint8_t shared) override;
-	void set_win_condition_script(std::string) override;
-	void next_win_condition() override;
+	void set_win_condition_script(const std::string&) override;
 	std::string get_win_condition_script() override;
 
 	// ChatProvider interface

=== modified file 'src/network/nethost.cc'
--- src/network/nethost.cc	2017-02-10 15:37:44 +0000
+++ src/network/nethost.cc	2017-04-07 12:02:48 +0000
@@ -268,23 +268,10 @@
 		return host_->settings().win_condition_script;
 	}
 
-	void set_win_condition_script(std::string wc) override {
+	void set_win_condition_script(const std::string& wc) override {
 		host_->set_win_condition_script(wc);
 	}
 
-	void next_win_condition() override {
-		if (wincondition_scripts_.empty()) {
-			wincondition_scripts_ = host_->settings().win_condition_scripts;
-			current_wincondition_ = -1;
-		}
-
-		if (can_change_map()) {
-			current_wincondition_++;
-			current_wincondition_ %= wincondition_scripts_.size();
-			set_win_condition_script(wincondition_scripts_[current_wincondition_]);
-		}
-	}
-
 private:
 	NetHost* host_;
 	int16_t current_wincondition_;
@@ -1377,7 +1364,7 @@
 	switch_to_player(0, number);
 }
 
-void NetHost::set_win_condition_script(std::string wc) {
+void NetHost::set_win_condition_script(const std::string& wc) {
 	d->settings.win_condition_script = wc;
 
 	// Broadcast changes

=== modified file 'src/network/nethost.h'
--- src/network/nethost.h	2017-01-25 18:55:59 +0000
+++ src/network/nethost.h	2017-04-07 12:02:48 +0000
@@ -76,7 +76,7 @@
 	void set_player_closeable(uint8_t number, bool closeable);
 	void set_player_shared(uint8_t number, uint8_t shared);
 	void switch_to_player(uint32_t user, uint8_t number);
-	void set_win_condition_script(std::string);
+	void set_win_condition_script(const std::string& wc);
 
 	// just visible stuff for the select mapmenu
 	void set_multiplayer_game_settings();

=== modified file 'src/ui_fsmenu/CMakeLists.txt'
--- src/ui_fsmenu/CMakeLists.txt	2017-02-28 20:07:07 +0000
+++ src/ui_fsmenu/CMakeLists.txt	2017-04-07 12:02:48 +0000
@@ -12,6 +12,8 @@
     internet_lobby.h
     intro.cc
     intro.h
+    launch_game.cc
+    launch_game.h
     launch_mpg.cc
     launch_mpg.h
     launch_spg.cc

=== added file 'src/ui_fsmenu/launch_game.cc'
--- src/ui_fsmenu/launch_game.cc	1970-01-01 00:00:00 +0000
+++ src/ui_fsmenu/launch_game.cc	2017-04-07 12:02:48 +0000
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2002-2016 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 "ui_fsmenu/launch_game.h"
+
+#include <memory>
+
+#include <boost/algorithm/string/predicate.hpp>
+
+#include "base/i18n.h"
+#include "base/warning.h"
+#include "base/wexception.h"
+#include "graphic/graphic.h"
+#include "graphic/text_constants.h"
+#include "logic/game.h"
+#include "logic/game_controller.h"
+#include "logic/game_settings.h"
+#include "logic/map_objects/map_object.h"
+#include "logic/player.h"
+#include "map_io/map_loader.h"
+#include "scripting/lua_interface.h"
+#include "scripting/lua_table.h"
+#include "ui_fsmenu/loadgame.h"
+#include "ui_fsmenu/mapselect.h"
+
+FullscreenMenuLaunchGame::FullscreenMenuLaunchGame(GameSettingsProvider* const settings,
+                                                   GameController* const ctrl)
+   : FullscreenMenuBase(),
+
+     // Values for alignment and size
+     butw_(get_w() / 4),
+     buth_(get_h() * 9 / 200),
+
+     win_condition_dropdown_(this,
+                             get_w() * 7 / 10,
+                             get_h() * 4 / 10 + buth_,
+                             butw_,
+                             get_h() - get_h() * 4 / 10 - buth_,
+                             buth_,
+                             ""),
+     ok_(this,
+         "ok",
+         0,
+         0,
+         butw_,
+         buth_,
+         g_gr->images().get("images/ui_basic/but2.png"),
+         _("Start game")),
+     back_(this,
+           "back",
+           0,
+           0,
+           butw_,
+           buth_,
+           g_gr->images().get("images/ui_basic/but0.png"),
+           _("Back")),
+     // Text labels
+	  title_(this, get_w() / 2, get_h() / 25, "", UI::Align::kCenter),
+     // Variables and objects used in the menu
+     settings_(settings),
+     ctrl_(ctrl),
+     nr_players_(0) {
+	win_condition_dropdown_.selected.connect(
+	   boost::bind(&FullscreenMenuLaunchGame::win_condition_selected, this));
+	back_.sigclicked.connect(
+	   boost::bind(&FullscreenMenuLaunchGame::clicked_back, boost::ref(*this)));
+	ok_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchGame::clicked_ok, boost::ref(*this)));
+
+	lua_ = new LuaInterface();
+
+	title_.set_fontsize(fs_big());
+}
+
+FullscreenMenuLaunchGame::~FullscreenMenuLaunchGame() {
+	delete lua_;
+}
+
+void FullscreenMenuLaunchGame::think() {
+	if (ctrl_)
+		ctrl_->think();
+
+	refresh();
+}
+
+bool FullscreenMenuLaunchGame::init_win_condition_label() {
+	if (settings_->settings().scenario) {
+		win_condition_dropdown_.set_label(_("Scenario"));
+		win_condition_dropdown_.set_tooltip(_("Win condition is set through the scenario"));
+		return true;
+	} else if (settings_->settings().savegame) {
+		/** Translators: This is a game type */
+		win_condition_dropdown_.set_label(_("Saved Game"));
+		win_condition_dropdown_.set_tooltip(
+		   _("The game is a saved game – the win condition was set before."));
+		return true;
+	} else {
+		win_condition_dropdown_.set_label("");
+		win_condition_dropdown_.set_tooltip("");
+		return false;
+	}
+}
+
+/**
+ * Fill the dropdown with the available win conditions.
+ */
+void FullscreenMenuLaunchGame::update_win_conditions() {
+	win_condition_dropdown_.set_enabled(settings_->can_change_map() &&
+	                                    !settings_->settings().savegame &&
+	                                    !settings_->settings().scenario);
+	if (!init_win_condition_label()) {
+		Widelands::Map map;
+		std::unique_ptr<Widelands::MapLoader> ml =
+		   map.get_correct_loader(settings_->settings().mapfilename);
+		if (ml != nullptr) {
+			ml->preload_map(true);
+			load_win_conditions(map);
+		} else {
+			const std::string error_message =
+			   (boost::format(_("Unable to determine valid win conditions because the map '%s' could "
+			                    "not be loaded.")) %
+			    settings_->settings().mapfilename)
+			      .str();
+			win_condition_dropdown_.set_label(_("Error"));
+			win_condition_dropdown_.set_tooltip(error_message);
+			log("Launch Game: No map loader: %s\n", error_message.c_str());
+		}
+	}
+}
+
+void FullscreenMenuLaunchGame::load_win_conditions(const Widelands::Map& map) {
+	win_condition_dropdown_.clear();
+	try {
+		const std::set<std::string> tags = map.get_tags();
+		// Make sure that the last win condition is still valid. If not, pick the first one
+		// available.
+		if (last_win_condition_.empty()) {
+			last_win_condition_ = settings_->settings().win_condition_scripts.front();
+		}
+		std::unique_ptr<LuaTable> t = win_condition_if_valid(last_win_condition_, tags);
+		for (const std::string& win_condition_script : settings_->settings().win_condition_scripts) {
+			if (t) {
+				break;
+			} else {
+				last_win_condition_ = win_condition_script;
+				t = win_condition_if_valid(last_win_condition_, tags);
+			}
+		}
+
+		// Now fill the dropdown.
+		for (const std::string& win_condition_script : settings_->settings().win_condition_scripts) {
+			try {
+				t = win_condition_if_valid(win_condition_script, tags);
+				if (t) {
+					i18n::Textdomain td("win_conditions");
+					win_condition_dropdown_.add(_(t->get_string("name")), win_condition_script, nullptr,
+					                            win_condition_script == last_win_condition_,
+					                            t->get_string("description"));
+				}
+			} catch (LuaTableKeyError& e) {
+				log("LaunchSPG: Error loading win condition: %s %s\n", win_condition_script.c_str(),
+				    e.what());
+			}
+		}
+	} catch (const std::exception& e) {
+		const std::string error_message =
+		   (boost::format(_("Unable to determine valid win conditions because the map '%s' "
+		                    "could not be loaded.")) %
+		    settings_->settings().mapfilename)
+		      .str();
+		win_condition_dropdown_.set_label(_("Error"));
+		win_condition_dropdown_.set_tooltip(error_message);
+		log("LaunchSPG: Exception: %s %s\n", error_message.c_str(), e.what());
+	}
+}
+
+std::unique_ptr<LuaTable>
+FullscreenMenuLaunchGame::win_condition_if_valid(const std::string& win_condition_script,
+                                                 std::set<std::string> tags) const {
+	bool is_usable = true;
+	std::unique_ptr<LuaTable> t;
+	try {
+		t = lua_->run_script(win_condition_script);
+		t->do_not_warn_about_unaccessed_keys();
+
+		// Skip this win condition if the map doesn't have all the required tags
+		if (t->has_key("map_tags")) {
+			for (const std::string& map_tag : t->get_table("map_tags")->array_entries<std::string>()) {
+				if (!tags.count(map_tag)) {
+					is_usable = false;
+					break;
+				}
+			}
+		}
+	} catch (LuaTableKeyError& e) {
+		log(
+		   "LaunchSPG: Error loading win condition: %s %s\n", win_condition_script.c_str(), e.what());
+	}
+	if (!is_usable) {
+		t.reset(nullptr);
+	}
+	return t;
+}
+
+// Implemented by subclasses
+void FullscreenMenuLaunchGame::clicked_ok() {
+	NEVER_HERE();
+}
+
+// Implemented by subclasses
+void FullscreenMenuLaunchGame::clicked_back() {
+	NEVER_HERE();
+}

=== added file 'src/ui_fsmenu/launch_game.h'
--- src/ui_fsmenu/launch_game.h	1970-01-01 00:00:00 +0000
+++ src/ui_fsmenu/launch_game.h	2017-04-07 12:02:48 +0000
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2002-2016 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 WL_UI_FSMENU_LAUNCH_GAME_H
+#define WL_UI_FSMENU_LAUNCH_GAME_H
+
+#include <memory>
+#include <string>
+
+#include "graphic/playercolor.h"
+#include "logic/map.h"
+#include "ui_basic/button.h"
+#include "ui_basic/dropdown.h"
+#include "ui_basic/multilinetextarea.h"
+#include "ui_basic/textarea.h"
+#include "ui_fsmenu/base.h"
+
+struct ChatProvider;
+class GameController;
+struct GameSettingsProvider;
+class LuaInterface;
+
+/**
+ * Fullscreen menu for setting map and mapsettings for single and multi player
+ * games.
+ *
+ */
+class FullscreenMenuLaunchGame : public FullscreenMenuBase {
+public:
+	FullscreenMenuLaunchGame(GameSettingsProvider*, GameController*);
+	~FullscreenMenuLaunchGame();
+
+	void think() override;
+
+	virtual void refresh() = 0;
+
+protected:
+	void clicked_ok() override;
+	void clicked_back() override;
+
+	LuaInterface* lua_;
+
+	/// Initializes the label and tooltip for the win condition dropdown and returns 'true' if this
+	/// is a scenario or a savegame.
+	/// Creates a blank label/tooltip and returns 'false' otherwise.
+	bool init_win_condition_label();
+
+	/// Loads all win conditions that can be played with the map into the selection dropdown.
+	/// Disables the dropdown if the map is a scenario.
+	void update_win_conditions();
+	/// Reads the win conditions that are available for the given map and adds the entries to the
+	/// dropdown.
+	void load_win_conditions(const Widelands::Map& map);
+	/// Remembers the win condition that is currently selected in the dropdown.
+	virtual void win_condition_selected() = 0;
+	/// If the win condition in 'win_condition_script' can be played with the map tags,
+	/// parses the win condition and returns it as a std::unique_ptr<LuaTable>.
+	/// If this win condition can't be played with the map tags, returns a unique_ptr to nullptr.
+	std::unique_ptr<LuaTable> win_condition_if_valid(const std::string& win_condition_script,
+	                                                 std::set<std::string> tags) const;
+
+	uint32_t butw_;
+	uint32_t buth_;
+
+	UI::Dropdown<std::string> win_condition_dropdown_;
+	std::string last_win_condition_;
+	UI::Button ok_, back_;
+	UI::Textarea title_;
+	GameSettingsProvider* settings_;
+	GameController* ctrl_;
+
+	Widelands::PlayerNumber nr_players_;
+};
+
+#endif  // end of include guard: WL_UI_FSMENU_LAUNCH_GAME_H

=== modified file 'src/ui_fsmenu/launch_mpg.cc'
--- src/ui_fsmenu/launch_mpg.cc	2017-02-23 19:38:51 +0000
+++ src/ui_fsmenu/launch_mpg.cc	2017-04-07 12:02:48 +0000
@@ -96,11 +96,8 @@
 
 FullscreenMenuLaunchMPG::FullscreenMenuLaunchMPG(GameSettingsProvider* const settings,
                                                  GameController* const ctrl)
-   : FullscreenMenuBase(),
-
+   : FullscreenMenuLaunchGame(settings, ctrl),
      // Values for alignment and size
-     butw_(get_w() / 4),
-     buth_(get_h() * 9 / 200),
      fs_(fs_small()),
      // TODO(GunChleoc): We still need to use these consistently. Just getting them in for now
      // so we can have the SuggestedTeamsBox
@@ -119,30 +116,6 @@
                          g_gr->images().get("images/ui_basic/but1.png"),
                          g_gr->images().get("images/wui/menus/menu_toggle_minimap.png"),
                          _("Change map or saved game")),
-     ok_(this,
-         "ok",
-         right_column_x_,
-         get_h() * 12 / 20 - 2 * label_height_,
-         butw_,
-         buth_,
-         g_gr->images().get("images/ui_basic/but2.png"),
-         _("Start game")),
-     back_(this,
-           "back",
-           right_column_x_,
-           get_h() * 218 / 240,
-           butw_,
-           buth_,
-           g_gr->images().get("images/ui_basic/but0.png"),
-           _("Back")),
-     wincondition_(this,
-                   "win_condition",
-                   right_column_x_,
-                   get_h() * 11 / 20 - 2 * label_height_,
-                   butw_,
-                   buth_,
-                   g_gr->images().get("images/ui_basic/but1.png"),
-                   ""),
      help_button_(this,
                   "help",
                   right_column_x_ + butw_ - buth_,
@@ -154,7 +127,6 @@
                   _("Show the help window")),
 
      // Text labels
-     title_(this, get_w() / 2, get_h() / 25, _("Multiplayer Game Setup"), UI::Align::kCenter),
      mapname_(this, right_column_x_, get_h() * 3 / 20, std::string()),
      clients_(this,
               // (get_w() * 57 / 80) is the width of the MultiPlayerSetupGroup
@@ -185,22 +157,17 @@
      help_(nullptr),
 
      // Variables and objects used in the menu
-     settings_(settings),
-     ctrl_(ctrl),
      chat_(nullptr) {
+	ok_.set_pos(Vector2i(right_column_x_, get_h() * 12 / 20 - 2 * label_height_));
+	back_.set_pos(Vector2i(right_column_x_, get_h() * 218 / 240));
+	win_condition_dropdown_.set_pos(
+	   Vector2i(right_column_x_, get_h() * 11 / 20 - 2 * label_height_));
+	title_.set_text(_("Multiplayer Game Setup"));
 	change_map_or_save_.sigclicked.connect(
 	   boost::bind(&FullscreenMenuLaunchMPG::change_map_or_save, boost::ref(*this)));
-	ok_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchMPG::clicked_ok, boost::ref(*this)));
-	back_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchMPG::clicked_back, boost::ref(*this)));
-	wincondition_.sigclicked.connect(
-	   boost::bind(&FullscreenMenuLaunchMPG::win_condition_clicked, boost::ref(*this)));
 	help_button_.sigclicked.connect(
 	   boost::bind(&FullscreenMenuLaunchMPG::help_clicked, boost::ref(*this)));
 
-	lua_ = new LuaInterface();
-	win_condition_clicked();
-
-	title_.set_fontsize(fs_big());
 	mapname_.set_fontsize(fs_);
 	mapname_.set_color(RGBColor(255, 255, 127));
 	clients_.set_fontsize(fs_);
@@ -232,7 +199,6 @@
 }
 
 FullscreenMenuLaunchMPG::~FullscreenMenuLaunchMPG() {
-	delete lua_;
 	delete mpsg_;
 	delete chat_;
 }
@@ -241,13 +207,6 @@
 	// TODO(GunChleoc): Implement when we have redesigned this
 }
 
-void FullscreenMenuLaunchMPG::think() {
-	if (ctrl_)
-		ctrl_->think();
-
-	refresh();
-}
-
 /**
  * Set a new chat provider.
  *
@@ -266,68 +225,11 @@
 	end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kBack);
 }
 
-/**
- * WinCondition button has been pressed
- */
-void FullscreenMenuLaunchMPG::win_condition_clicked() {
-	settings_->next_win_condition();
-	win_condition_update();
-}
-
-/**
- * update win conditions information
- */
-void FullscreenMenuLaunchMPG::win_condition_update() {
-	if (settings_->settings().scenario) {
-		wincondition_.set_title(_("Scenario"));
-		wincondition_.set_tooltip(_("Win condition is set through the scenario"));
-	} else if (settings_->settings().savegame) {
-		/** Translators: This is a game type */
-		wincondition_.set_title(_("Saved Game"));
-		wincondition_.set_tooltip(_("The game is a saved game – the win condition was set before."));
-	} else {
-		win_condition_load();
-	}
-}
-
-/**
- * Loads the current win condition script from the settings provider.
- * Calls win_condition_clicked() if the current map can't handle the win condition.
- */
-void FullscreenMenuLaunchMPG::win_condition_load() {
-	bool is_usable = true;
-	try {
-		std::unique_ptr<LuaTable> t = lua_->run_script(settings_->get_win_condition_script());
-		t->do_not_warn_about_unaccessed_keys();
-
-		// Skip this win condition if the map doesn't have all the required tags
-		if (t->has_key("map_tags") && !settings_->settings().mapfilename.empty()) {
-			Widelands::Map map;
-			std::unique_ptr<Widelands::MapLoader> ml =
-			   map.get_correct_loader(settings_->settings().mapfilename);
-			ml->preload_map(true);
-			for (const std::string& map_tag : t->get_table("map_tags")->array_entries<std::string>()) {
-				if (!map.has_tag(map_tag)) {
-					is_usable = false;
-					break;
-				}
-			}
-		}
-
-		std::string name = t->get_string("name");
-		std::string descr = t->get_string("description");
-
-		{
-			i18n::Textdomain td("win_conditions");
-			wincondition_.set_title(_(name));
-		}
-		wincondition_.set_tooltip(descr.c_str());
-	} catch (LuaTableKeyError&) {
-		// might be that this is not a win condition after all.
-		is_usable = false;
-	}
-	if (!is_usable) {
-		win_condition_clicked();
+void FullscreenMenuLaunchMPG::win_condition_selected() {
+	// last_win_condition_ = win_condition_dropdown_.get_selected();
+	if (settings_->can_change_map()) {
+		settings_->set_win_condition_script(win_condition_dropdown_.get_selected());
+		last_win_condition_ = win_condition_dropdown_.get_selected();
 	}
 }
 
@@ -343,6 +245,7 @@
 	} else if (result == FullscreenMenuBase::MenuTarget::kScenarioGame) {
 		select_saved_game();
 	}
+	update_win_conditions();
 }
 
 /**
@@ -440,8 +343,10 @@
 		                  "from the host to you, but perhaps the transfer was not yet "
 		                  "finished!?!"),
 		                settings_->settings().mapfilename.c_str());
-	if (settings_->can_launch())
+	if (settings_->can_launch()) {
+		settings_->set_win_condition_script(win_condition_dropdown_.get_selected());
 		end_modal<FullscreenMenuBase::MenuTarget>(FullscreenMenuBase::MenuTarget::kNormalGame);
+	}
 }
 
 /**
@@ -496,11 +401,22 @@
 	change_map_or_save_.set_enabled(settings_->can_change_map());
 	change_map_or_save_.set_visible(settings_->can_change_map());
 
-	wincondition_.set_enabled(settings_->can_change_map() && !settings.savegame &&
-	                          !settings.scenario);
-
-	win_condition_update();
-
+	if (!settings_->can_change_map() && !init_win_condition_label()) {
+		try {
+			// We do not validate the scripts for the client - it's only a label.
+			std::unique_ptr<LuaTable> t = lua_->run_script(settings_->get_win_condition_script());
+			t->do_not_warn_about_unaccessed_keys();
+			if (t) {
+				i18n::Textdomain td("win_conditions");
+				win_condition_dropdown_.set_label(_(t->get_string("name")));
+				win_condition_dropdown_.set_tooltip(_(t->get_string("description")));
+			}
+		} catch (LuaTableKeyError& e) {
+			log("LaunchMPG: Error loading win condition: %s %s\n",
+			    settings_->get_win_condition_script().c_str(), e.what());
+		}
+		win_condition_dropdown_.set_enabled(false);
+	}
 	// Update the multi player setup group
 	mpsg_->refresh();
 }

=== modified file 'src/ui_fsmenu/launch_mpg.h'
--- src/ui_fsmenu/launch_mpg.h	2017-01-25 18:55:59 +0000
+++ src/ui_fsmenu/launch_mpg.h	2017-04-07 12:02:48 +0000
@@ -24,10 +24,11 @@
 #include <string>
 
 #include "ui_basic/button.h"
+#include "ui_basic/dropdown.h"
 #include "ui_basic/multilinetextarea.h"
 #include "ui_basic/textarea.h"
-#include "ui_fsmenu/base.h"
 #include "ui_fsmenu/helpwindow.h"
+#include "ui_fsmenu/launch_game.h"
 #include "wui/suggested_teams_box.h"
 
 struct ChatProvider;
@@ -42,16 +43,13 @@
  * games.
  *
  */
-class FullscreenMenuLaunchMPG : public FullscreenMenuBase {
+class FullscreenMenuLaunchMPG : public FullscreenMenuLaunchGame {
 public:
 	FullscreenMenuLaunchMPG(GameSettingsProvider*, GameController*);
 	~FullscreenMenuLaunchMPG();
 
 	void set_chat_provider(ChatProvider&);
-
-	void think() override;
-
-	void refresh();
+	void refresh() override;
 
 protected:
 	void clicked_ok() override;
@@ -60,21 +58,16 @@
 private:
 	void layout() override;
 
-	LuaInterface* lua_;
-
 	void change_map_or_save();
 	void select_map();
 	void select_saved_game();
-	void win_condition_clicked();
-	void win_condition_update();
-	void win_condition_load();
+	void win_condition_selected() override;
+
 	void set_scenario_values();
 	void load_previous_playerdata();
 	void load_map_info();
 	void help_clicked();
 
-	uint32_t butw_;
-	uint32_t buth_;
 	uint32_t fs_;
 
 	// TODO(GunChleoc): We still need to use these consistently. Just getting them in for now
@@ -84,17 +77,14 @@
 	int32_t const label_height_;
 	int32_t const right_column_x_;
 
-	UI::Button change_map_or_save_, ok_, back_, wincondition_;
+	UI::Button change_map_or_save_;
 	UI::Button help_button_;
-	UI::Textarea title_, mapname_, clients_, players_, map_, wincondition_type_;
+	UI::Textarea mapname_, clients_, players_, map_, wincondition_type_;
 	UI::MultilineTextarea map_info_, client_info_;
 	std::unique_ptr<UI::FullscreenHelpWindow> help_;
-	GameSettingsProvider* settings_;
-	GameController* ctrl_;
 	GameChatPanel* chat_;
 	MultiPlayerSetupGroup* mpsg_;
 	std::string filename_proof_;  // local variable to check state
-	int16_t nr_players_;
 
 	UI::SuggestedTeamsBox* suggested_teams_box_;
 };

=== modified file 'src/ui_fsmenu/launch_spg.cc'
--- src/ui_fsmenu/launch_spg.cc	2017-03-06 06:57:47 +0000
+++ src/ui_fsmenu/launch_spg.cc	2017-04-07 12:02:48 +0000
@@ -43,14 +43,8 @@
 #include "wui/playerdescrgroup.h"
 
 FullscreenMenuLaunchSPG::FullscreenMenuLaunchSPG(GameSettingsProvider* const settings,
-                                                 GameController* const ctrl,
-                                                 bool /* autolaunch */)
-   : FullscreenMenuBase(),
-
-     // Values for alignment and size
-     butw_(get_w() / 4),
-     buth_(get_h() * 9 / 200),
-
+                                                 GameController* const ctrl)
+   : FullscreenMenuLaunchGame(settings, ctrl),
      // Buttons
      select_map_(this,
                  "select_map",
@@ -60,32 +54,8 @@
                  buth_,
                  g_gr->images().get("images/ui_basic/but1.png"),
                  _("Select map")),
-     win_condition_dropdown_(this,
-                             get_w() * 7 / 10,
-                             get_h() * 4 / 10 + buth_,
-                             butw_,
-                             get_h() - get_h() * 4 / 10 - buth_,
-                             buth_,
-                             ""),
-     back_(this,
-           "back",
-           get_w() * 7 / 10,
-           get_h() * 17 / 20,
-           butw_,
-           buth_,
-           g_gr->images().get("images/ui_basic/but0.png"),
-           _("Back")),
-     ok_(this,
-         "ok",
-         get_w() * 7 / 10,
-         get_h() * 9 / 10,
-         butw_,
-         buth_,
-         g_gr->images().get("images/ui_basic/but2.png"),
-         _("Start game")),
 
      // Text labels
-     title_(this, get_w() / 2, get_h() / 10, _("Launch Game"), UI::Align::kCenter),
      mapname_(this,
               get_w() * 7 / 10 + butw_ / 2,
               get_h() * 53 / 200 - 15,
@@ -114,19 +84,13 @@
                         UI::Align::kCenter),
 
      // Variables and objects used in the menu
-     settings_(settings),
-     ctrl_(ctrl),
      is_scenario_(false) {
+	ok_.set_pos(Vector2i(get_w() * 7 / 10, get_h() * 9 / 10));
+	back_.set_pos(Vector2i(get_w() * 7 / 10, get_h() * 17 / 20));
+	win_condition_dropdown_.set_pos(Vector2i(get_w() * 7 / 10, get_h() * 4 / 10 + buth_));
+	title_.set_text(_("Launch Game"));
 	select_map_.sigclicked.connect(
 	   boost::bind(&FullscreenMenuLaunchSPG::select_map, boost::ref(*this)));
-	win_condition_dropdown_.selected.connect(
-	   boost::bind(&FullscreenMenuLaunchSPG::win_condition_selected, this));
-	back_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchSPG::clicked_back, boost::ref(*this)));
-	ok_.sigclicked.connect(boost::bind(&FullscreenMenuLaunchSPG::clicked_ok, boost::ref(*this)));
-
-	lua_ = new LuaInterface();
-
-	title_.set_fontsize(UI_FONT_SIZE_BIG);
 
 	int smaller_fontsize = fs_small() * 4 / 5;
 	name_.set_fontsize(smaller_fontsize);
@@ -155,7 +119,6 @@
 }
 
 FullscreenMenuLaunchSPG::~FullscreenMenuLaunchSPG() {
-	delete lua_;
 }
 
 void FullscreenMenuLaunchSPG::layout() {
@@ -173,13 +136,6 @@
 	}
 }
 
-void FullscreenMenuLaunchSPG::think() {
-	if (ctrl_)
-		ctrl_->think();
-
-	refresh();
-}
-
 /**
  * back-button has been pressed
  */
@@ -195,116 +151,10 @@
 	refresh();
 }
 
-/**
- * Fill the dropdown with the available win conditions.
- */
-void FullscreenMenuLaunchSPG::update_win_conditions() {
-	win_condition_dropdown_.clear();
-	if (settings_->settings().scenario) {
-		win_condition_dropdown_.set_label(_("Scenario"));
-		win_condition_dropdown_.set_tooltip(_("Win condition is set through the scenario"));
-		win_condition_dropdown_.set_enabled(false);
-	} else {
-		win_condition_dropdown_.set_label("");
-		win_condition_dropdown_.set_tooltip("");
-		Widelands::Map map;
-		std::unique_ptr<Widelands::MapLoader> ml =
-		   map.get_correct_loader(settings_->settings().mapfilename);
-		if (ml != nullptr) {
-			ml->preload_map(true);
-			load_win_conditions(map);
-		} else {
-			const std::string error_message =
-			   (boost::format(_("Unable to determine valid win conditions because the map '%s' could "
-			                    "not be loaded.")) %
-			    settings_->settings().mapfilename)
-			      .str();
-			win_condition_dropdown_.set_label(_("Error"));
-			win_condition_dropdown_.set_tooltip(error_message);
-			log("LaunchSPG: No map loader: %s\n", error_message.c_str());
-		}
-		win_condition_dropdown_.set_enabled(true);
-	}
-}
-
-void FullscreenMenuLaunchSPG::load_win_conditions(const Widelands::Map& map) {
-	try {
-		const std::set<std::string> tags = map.get_tags();
-		// Make sure that the last win condition is still valid. If not, pick the first one
-		// available.
-		if (last_win_condition_.empty()) {
-			last_win_condition_ = settings_->settings().win_condition_scripts.front();
-		}
-		std::unique_ptr<LuaTable> t = win_condition_if_valid(last_win_condition_, tags);
-		for (const std::string& win_condition_script : settings_->settings().win_condition_scripts) {
-			if (t) {
-				break;
-			} else {
-				last_win_condition_ = win_condition_script;
-				t = win_condition_if_valid(last_win_condition_, tags);
-			}
-		}
-
-		// Now fill the dropdown.
-		for (const std::string& win_condition_script : settings_->settings().win_condition_scripts) {
-			try {
-				t = win_condition_if_valid(win_condition_script, tags);
-				if (t) {
-					i18n::Textdomain td("win_conditions");
-					win_condition_dropdown_.add(_(t->get_string("name")), win_condition_script, nullptr,
-					                            win_condition_script == last_win_condition_,
-					                            t->get_string("description"));
-				}
-			} catch (LuaTableKeyError& e) {
-				log("LaunchSPG: Error loading win condition: %s %s\n", win_condition_script.c_str(),
-				    e.what());
-			}
-		}
-	} catch (const std::exception& e) {
-		const std::string error_message =
-		   (boost::format(_("Unable to determine valid win conditions because the map '%s' "
-		                    "could not be loaded.")) %
-		    settings_->settings().mapfilename)
-		      .str();
-		win_condition_dropdown_.set_label(_("Error"));
-		win_condition_dropdown_.set_tooltip(error_message);
-		log("LaunchSPG: Exception: %s %s\n", error_message.c_str(), e.what());
-	}
-}
-
 void FullscreenMenuLaunchSPG::win_condition_selected() {
 	last_win_condition_ = win_condition_dropdown_.get_selected();
 }
 
-// TODO(GunChleoc): Turn this into a free standing function. It seems it is not using any state.
-std::unique_ptr<LuaTable>
-FullscreenMenuLaunchSPG::win_condition_if_valid(const std::string& win_condition_script,
-                                                std::set<std::string> tags) const {
-	bool is_usable = true;
-	std::unique_ptr<LuaTable> t;
-	try {
-		t = lua_->run_script(win_condition_script);
-		t->do_not_warn_about_unaccessed_keys();
-
-		// Skip this win condition if the map doesn't have all the required tags
-		if (t->has_key("map_tags")) {
-			for (const std::string& map_tag : t->get_table("map_tags")->array_entries<std::string>()) {
-				if (!tags.count(map_tag)) {
-					is_usable = false;
-					break;
-				}
-			}
-		}
-	} catch (LuaTableKeyError& e) {
-		log(
-		   "LaunchSPG: Error loading win condition: %s %s\n", win_condition_script.c_str(), e.what());
-	}
-	if (!is_usable) {
-		t.reset(nullptr);
-	}
-	return t;
-}
-
 /**
  * start-button has been pressed
  */

=== modified file 'src/ui_fsmenu/launch_spg.h'
--- src/ui_fsmenu/launch_spg.h	2017-01-25 18:55:59 +0000
+++ src/ui_fsmenu/launch_spg.h	2017-04-07 12:02:48 +0000
@@ -29,7 +29,7 @@
 #include "ui_basic/dropdown.h"
 #include "ui_basic/multilinetextarea.h"
 #include "ui_basic/textarea.h"
-#include "ui_fsmenu/base.h"
+#include "ui_fsmenu/launch_game.h"
 
 struct ChatProvider;
 class GameController;
@@ -47,17 +47,13 @@
  *                               change the map.
  *
  */
-class FullscreenMenuLaunchSPG : public FullscreenMenuBase {
+class FullscreenMenuLaunchSPG : public FullscreenMenuLaunchGame {
 public:
-	FullscreenMenuLaunchSPG(GameSettingsProvider*,
-	                        GameController* = nullptr,
-	                        bool autolaunch = false);
+	FullscreenMenuLaunchSPG(GameSettingsProvider*, GameController* = nullptr);
 	~FullscreenMenuLaunchSPG();
 
-	void start() override;
-	void think() override;
-
-	void refresh();
+	void start();
+	void refresh() override;
 
 protected:
 	void clicked_ok() override;
@@ -66,44 +62,21 @@
 private:
 	void layout() override;
 
-	LuaInterface* lua_;
-
 	void select_map();
-	/// Loads all win conditions that can be played with the map into the selection dropdown.
-	/// Disables the dropdown if the map is a scenario.
-	void update_win_conditions();
-	/// Reads the win conditions that are available for the given map and adds the entries to the
-	/// dropdown.
-	void load_win_conditions(const Widelands::Map& map);
-	/// Remembers the win condition that is currently selected in the dropdown.
-	void win_condition_selected();
-	/// If the win condition in 'win_condition_script' can be played with the map tags,
-	/// parses the win condition and returns it as a std::unique_ptr<LuaTable>.
-	/// If this win condition can't be played with the map tags, returns a unique_ptr to nullptr.
-	std::unique_ptr<LuaTable> win_condition_if_valid(const std::string& win_condition_script,
-	                                                 std::set<std::string> tags) const;
+	void win_condition_selected() override;
 	void set_scenario_values();
 	void switch_to_position(uint8_t);
 	void safe_place_for_host(uint8_t);
 
-	uint32_t butw_;
-	uint32_t buth_;
-
 	UI::Button select_map_;
-	UI::Dropdown<std::string> win_condition_dropdown_;
-	std::string last_win_condition_;
-	UI::Button back_, ok_;
 	UI::Button* pos_[kMaxPlayers];
-	UI::Textarea title_, mapname_;
+	UI::Textarea mapname_;
 	UI::Textarea name_, type_, team_, tribe_, init_, wincondition_type_;
-	GameSettingsProvider* settings_;
-	GameController* ctrl_;  // optional
 	PlayerDescriptionGroup* players_[kMaxPlayers];
 	std::string filename_;
 	std::string filename_proof_;  // local var. to check UI state
 	std::string player_save_name_[kMaxPlayers];
 	std::string player_save_tribe_[kMaxPlayers];
-	int8_t nr_players_;
 	bool is_scenario_;
 };
 


Follow ups