Index: changelog
===================================================================
--- changelog	(revision 54884)
+++ changelog	(working copy)
@@ -167,6 +167,8 @@
    * Changes to the time of day schedules of Fallenstar Lake and Silverhead
      Crossing
    * Random leader is default selection when picking faction
+   * Added support for modification tags
+   * Added support for dependencies between eras, scenarios and modifications
  * Music and sound effects:
    * Replaced some of the wolf hit sounds with lower-pitched ones
  * Terrain:
Index: data/gui/default/window/mp_create_game_choose_mods.cfg
===================================================================
--- data/gui/default/window/mp_create_game_choose_mods.cfg	(revision 0)
+++ data/gui/default/window/mp_create_game_choose_mods.cfg	(working copy)
@@ -0,0 +1,220 @@
+#textdomain wesnoth-lib
+###
+### Select the modifications to be active during the game
+###
+
+[window]
+	id = "mp_create_game_choose_mods"
+	description = "Dialog for choosing modifications for MP games."
+
+	[resolution]
+		definition = "default"
+
+		automatic_placement = "true"
+		vertical_placement = "center"
+		horizontal_placement = "center"
+
+		[linked_group]
+			id = "checkbox"
+			fixed_width = "true"
+		[/linked_group]
+
+		[linked_group]
+			id = "name"
+			fixed_width = "true"
+		[/linked_group]
+
+		[linked_group]
+			id = "description"
+			fixed_width = "true"
+		[/linked_group]
+
+		[tooltip]
+			id = "tooltip_large"
+		[/tooltip]
+
+		[helptip]
+			id = "tooltip_large"
+		[/helptip]
+
+		[grid]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+					grow_factor = 1
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "left"
+					[label]
+						definition = "title"
+
+						label = _ "Choose Modifications"
+					[/label]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "left"
+					[label]
+						definition = "default"
+						id = "message"
+
+						label = _ "Enable the modifications you want to be active during the game."
+					[/label]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 1
+
+				[column]
+					grow_factor = 1
+
+					horizontal_grow = "true"
+					vertical_grow = "true"
+
+					border = "all"
+					border_size = 5
+
+					[listbox]
+						id = "mod_list"
+						definition = "default"
+
+						[list_definition]
+
+							[row]
+
+								[column]
+								 	vertical_grow = "true"
+								 	horizontal_grow = "true"
+								 	[toggle_panel]
+										definition = "default"
+										[grid]
+											[row]
+												[column]
+													grow_factor = 0
+													horizontal_alignment = "left"
+													border = "all"
+													border_size = 5
+													[toggle_button]
+														id = "checkbox"
+														definition = "default"
+														linked_group = "checkbox"
+													[/toggle_button]
+												[/column]
+												[column]
+													grow_factor = 1
+													horizontal_grow = "true"
+													border = "all"
+													border_size = 5
+													[label]
+														id = "name"
+														definition = "default_large"
+														linked_group = "name"
+													[/label]
+												[/column]
+											[/row]
+											[row]
+												[column]
+													grow_factor = 0
+													horizontal_alignment = "left"
+													border = "all"
+													border_size = 5
+													[spacer]
+													[/spacer]
+												[/column]
+												[column]
+													grow_factor = 1
+													horizontal_alignment = "left"
+													border = "all"
+													border_size = 5
+													[label]
+														id = "description"
+														definition = "default"
+														linked_group = "description"
+													[/label]
+												[/column]
+											[/row]
+										[/grid]
+									[/toggle_panel]
+								[/column]
+
+							[/row]
+
+						[/list_definition]
+
+					[/listbox]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "right"
+
+					[grid]
+
+						[row]
+
+							[column]
+
+								border = "all"
+								border_size = 5
+								horizontal_alignment = "right"
+
+								[button]
+									id = "ok"
+									definition = "default"
+
+									label = _ "OK"
+								[/button]
+							[/column]
+
+							[column]
+
+								border = "all"
+								border_size = 5
+								horizontal_alignment = "right"
+
+								[button]
+									id = "cancel"
+									definition = "default"
+
+									label = _ "Cancel"
+								[/button]
+
+							[/column]
+
+						[/row]
+
+					[/grid]
+
+				[/column]
+
+			[/row]
+
+		[/grid]
+
+	[/resolution]
+
+[/window]
+ 
Index: data/gui/default/window/mp_depcheck_confirm_change.cfg
===================================================================
--- data/gui/default/window/mp_depcheck_confirm_change.cfg	(revision 0)
+++ data/gui/default/window/mp_depcheck_confirm_change.cfg	(working copy)
@@ -0,0 +1,161 @@
+#textdomain wesnoth-lib
+###
+### Prompts the user to confirm some changes required to satisfy 
+### dependencies. Currently used for enabling/disabling modifications.
+###
+
+[window]
+	id = "mp_depcheck_confirm_change"
+	description = "Enable/disable modifications"
+
+	[resolution]
+		definition = "default"
+
+		automatic_placement = "true"
+		vertical_placement = "center"
+		horizontal_placement = "center"
+
+		[tooltip]
+			id = "tooltip_large"
+		[/tooltip]
+
+		[helptip]
+			id = "tooltip_large"
+		[/helptip]
+ 
+		[grid]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+					grow_factor = 1
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "left"
+
+					[label]
+						definition = "title"
+						label = _ "Confirmation requested"
+					[/label]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+					grow_factor = 1
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "left"
+
+					[label]
+						definition = "default"
+						label = "text is set by C++"
+						id = "message"
+					[/label]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 1
+
+				[column]
+					grow_factor = 1
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "left"
+
+					[scroll_label]
+						id = "itemlist"
+						label = "text set by c++"
+						definition = "default"
+					[/scroll_label]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+					grow_factor = 1
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "left"
+
+					[label]
+						label = _ "Would you like to apply the changes?"
+						definition = "default"
+					[/label]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+					grow_factor = 1
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "right"
+
+					[grid]
+
+						[row]
+							grow_factor = 0
+
+							[column]
+								grow_factor = 0
+
+								border = "all"
+								border_size = 5
+								horizontal_alignment = "center"
+
+								[button]
+									id = "ok"
+									label = _ "Yes"
+								[/button]
+
+							[/column]
+
+							[column]
+								grow_factor = 1
+
+								border = "all"
+								border_size = 5
+								horizontal_alignment = "right"
+
+								[button]
+									id = "cancel"
+									label = _ "No"
+								[/button]
+
+							[/column]
+
+						[/row]
+
+					[/grid]
+
+				[/column]
+
+			[/row]
+
+		[/grid]
+
+	[/resolution]
+
+[/window]
Index: data/gui/default/window/mp_depcheck_select_new.cfg
===================================================================
--- data/gui/default/window/mp_depcheck_select_new.cfg	(revision 0)
+++ data/gui/default/window/mp_depcheck_select_new.cfg	(working copy)
@@ -0,0 +1,164 @@
+#textdomain wesnoth-lib
+###
+### Proposes a list of compaitble components if the currently selected
+### one is incompatible. Currently used for scenarios and eras.
+###
+
+[window]
+	id = "mp_depcheck_select_new"
+	description = "Select new era or scenario"
+
+	[resolution]
+		definition = "default"
+
+		automatic_placement = "true"
+		horizontal_placement = "center"
+		vertical_placement = "center"
+
+		[tooltip]
+			id = "tooltip_large"
+		[/tooltip]
+
+		[helptip]
+			id = "tooltip_large"
+		[/helptip]
+
+		[grid]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+					grow_factor = 1
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "left"
+
+					[label]
+						definition = "title"
+						label = _ "User interaction required"
+					[/label]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+					grow_factor = 1
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "left"
+
+					[label]
+						definition = "default"
+						label = _ "User interaction required"
+						id = "message"
+					[/label]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 1
+
+				[column]
+					grow_factor = 1
+					horizontal_grow = "true"
+					vertical_grow = "true"
+
+					border = "all"
+					border_size = 5
+
+					[listbox]
+						definition = "default"
+						id = "itemlist"
+
+						[list_definition]
+
+							[row]
+
+								[column]
+									grow_factor = 1
+									horizontal_grow = "true"
+
+									[toggle_button]
+										definition = "listbox_text"
+
+										return_value_id = "ok"
+									[/toggle_button]
+
+								[/column]
+
+							[/row]
+
+						[/list_definition]
+
+					[/listbox]
+
+				[/column]
+
+			[/row]
+
+			[row]
+				grow_factor = 0
+
+				[column]
+					grow_factor = 1
+
+					border = "all"
+					border_size = 5
+					horizontal_alignment = "right"
+
+					[grid]
+
+						[row]
+							grow_factor = 0
+
+							[column]
+								grow_factor = 0
+
+								border = "all"
+								border_size = 5
+								horizontal_alignment = "center"
+
+								[button]
+									id = "ok"
+									label = _ "OK"
+								[/button]
+
+							[/column]
+
+							[column]
+								grow_factor = 1
+
+								border = "all"
+								border_size = 5
+								horizontal_alignment = "right"
+
+								[button]
+									id = "cancel"
+									label = _ "Cancel"
+								[/button]
+
+							[/column]
+
+
+						[/row]
+
+					[/grid]
+
+				[/column]
+
+			[/row]
+
+		[/grid]
+
+	[/resolution]
+
+[/window]
Index: src/mp_game_settings.cpp
===================================================================
--- src/mp_game_settings.cpp	(revision 54884)
+++ src/mp_game_settings.cpp	(working copy)
@@ -20,6 +20,7 @@
  */
 
 #include "mp_game_settings.hpp"
+#include "formula_string_utils.hpp"
 
 mp_game_settings::mp_game_settings() :
 	savegame_config(),
@@ -28,6 +29,7 @@
 	hash(),
 	mp_era(),
 	mp_scenario(),
+	active_mods(),
 	village_gold(0),
 	village_support(1),
 	xp_modifier(0),
@@ -45,6 +47,7 @@
 	share_view(false),
 	share_maps(false),
 	saved_game(false),
+	options(),
 	scenario_data()
 
 { reset(); }
@@ -56,6 +59,7 @@
 	hash(),
 	mp_era(),
 	mp_scenario(),
+	active_mods(),
 	village_gold(0),
 	village_support(1),
 	xp_modifier(0),
@@ -73,6 +77,7 @@
 	share_view(false),
 	share_maps(false),
 	saved_game(false),
+	options(),
 	scenario_data()
 {
 	set_from_config(cfg);
@@ -85,6 +90,7 @@
 	, hash(settings.hash)
 	, mp_era(settings.mp_era)
 	, mp_scenario(settings.mp_scenario)
+	, active_mods(settings.active_mods)
 	, village_gold(settings.village_gold)
 	, village_support(settings.village_support)
 	, xp_modifier(settings.xp_modifier)
@@ -102,6 +108,7 @@
 	, share_view(settings.share_view)
 	, share_maps(settings.share_maps)
 	, saved_game(settings.saved_game)
+	, options(settings.options)
 	, scenario_data(settings.scenario_data)
 {
 }
@@ -116,6 +123,7 @@
 	hash = cfg["hash"].str();
 	mp_era = cfg["mp_era"].str();
 	mp_scenario = cfg["mp_scenario"].str();
+	active_mods = utils::split(cfg["active_mods"], ',');
 	xp_modifier = cfg["experience_modifier"];
 	use_map_settings = cfg["mp_use_map_settings"].to_bool();
 	fog_game = cfg["mp_fog"].to_bool();
@@ -130,6 +138,7 @@
 	allow_observers = cfg["observer"].to_bool();
 	shuffle_sides = cfg["shuffle_sides"].to_bool();
 	saved_game = cfg["savegame"].to_bool();
+	options = cfg.child_or_empty("options");
 }
 
 void mp_game_settings::reset()
@@ -139,6 +148,7 @@
 	hash = "";
 	mp_era = "";
 	mp_scenario = "";
+	active_mods.clear();
 	village_gold = 0;
 	village_support = 1;
 	xp_modifier = 0;
@@ -148,6 +158,7 @@
 	mp_countdown_action_bonus=0;
 	mp_countdown=false;
 	use_map_settings = random_start_time = fog_game = shroud_game = allow_observers = shuffle_sides = share_view = share_maps = false;
+	options.clear();
 
 	scenario_data.clear();
 }
@@ -160,6 +171,7 @@
 	cfg["hash"] = hash;
 	cfg["mp_era"] = mp_era;
 	cfg["mp_scenario"] = mp_scenario;
+	cfg["active_mods"] = utils::join(active_mods, ",");
 	cfg["experience_modifier"] = xp_modifier;
 	cfg["mp_countdown"] = mp_countdown;
 	cfg["mp_countdown_init_time"] = mp_countdown_init_time;
@@ -174,6 +186,7 @@
 	cfg["observer"] = allow_observers;
 	cfg["shuffle_sides"] = shuffle_sides;
 	cfg["savegame"] = saved_game;
+	cfg.add_child("options", options);
 
 	return cfg;
 }
Index: src/SConscript
===================================================================
--- src/SConscript	(revision 54884)
+++ src/SConscript	(working copy)
@@ -358,7 +358,10 @@
     gui/dialogs/mp_change_control.cpp
     gui/dialogs/mp_connect.cpp
     gui/dialogs/mp_create_game.cpp
+    gui/dialogs/mp_create_game_choose_mods.cpp
     gui/dialogs/mp_create_game_set_password.cpp
+    gui/dialogs/mp_depcheck_confirm_change.cpp
+    gui/dialogs/mp_depcheck_select_new.cpp
     gui/dialogs/mp_host_game_prompt.cpp
     gui/dialogs/mp_login.cpp
     gui/dialogs/mp_method_selection.cpp
@@ -418,6 +421,7 @@
     menu_events.cpp
     mouse_events.cpp
     mouse_handler_base.cpp
+    mp_depcheck.cpp
     mp_game_settings.cpp
     multiplayer.cpp
     multiplayer_connect.cpp
Index: src/mp_depcheck.hpp
===================================================================
--- src/mp_depcheck.hpp	(revision 0)
+++ src/mp_depcheck.hpp	(working copy)
@@ -0,0 +1,337 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#ifndef MP_DEPCHECK_HPP_INCLUDED
+#define MP_DEPCHECK_HPP_INCLUDED
+
+#include <string>
+#include <vector>
+#include <map>
+#include "config.hpp"
+#include "game_display.hpp"
+
+namespace mp
+{
+
+namespace depcheck
+{
+
+enum component_type
+{
+	ERA,
+	SCENARIO,
+	MODIFICATION
+};
+
+/**
+ * Note to all triers:
+ * It's not guaranteed that the specified component will be selected
+ * (if the user denies to perform dependency resolution, all changes
+ * will be reverted). Consequently, it's essential to check the 
+ * selected values after calling any trier.
+ * 
+ * Note to ctor & insert_element:
+ * Please note that the ctor collects data for scenario elements from 
+ * "multiplayer" nodes, while insert_element from "scenario" nodes.
+ */
+class manager
+{
+public:
+	manager(const config& gamecfg, CVideo& video);
+
+	/**
+	 * Tries to set the selected era
+	 * 
+	 * @param id 		the id of the era
+	 * @param force 	whether to skip dependency check
+	 */
+	void try_era(const std::string& id, bool force = false);
+
+	/**
+	 * Tries to set the selected scenario
+	 * 
+	 * @param id 		the id of the scenario
+	 * @param force 	whether to skip dependency check
+	 */
+	void try_scenario(const std::string& id, bool force = false);
+
+	/**
+	 * Tries to set the enabled modifications
+	 * 
+	 * @param ids 		the ids of the modifications
+	 * @param force 	whether to skip dependency check
+	 */
+	void try_modifications(const std::vector<std::string>& ids,
+						   bool force = false	);
+
+	/**
+	 * Tries to set the selected era
+	 * 
+	 * @param index 	the index of the era
+	 * @param force 	whether to skip dependency check
+	 */
+	void try_era_by_index(int index, bool force = false);
+
+	/**
+	 * Tries to set the selected scenario
+	 * 
+	 * @param index 	the index of the scenario
+	 * @param force 	whether to skip dependency check
+	 */
+	void try_scenario_by_index(int index, bool force = false);
+
+	/**
+	 * Returns the selected era
+	 * 
+	 * @return the id of the era
+	 */
+	const std::string& get_era() const { return era_; }
+
+	/**
+	 * Returns the selected scenario
+	 * 
+	 * @return the id of the scenario
+	 */
+	const std::string& get_scenario() const { return scenario_; }
+
+	/**
+	 * Returns the enabled modifications
+	 * 
+	 * @return the ids of the modifications
+	 */
+	const std::vector<std::string>& get_modifications() const { return mods_; }
+
+	/**
+	 * Returns the selected era
+	 * 
+	 * @return the index of the era
+	 */
+	int get_era_index() const;
+
+	/**
+	 * Returns the selected scenario
+	 * 
+	 * @return the index of the scenario
+	 */
+	int get_scenario_index() const;
+
+	/**
+	 * Adds a new element to the manager's database
+	 * 
+	 * @param type 		the type of the element
+	 * @param data 		a config object containing the dependency info for the
+	 * 					element
+	 * @param index 	where to insert the element
+	 */
+	void insert_element(component_type type, const config& data, int index = 0);
+
+private:
+
+	/** represents a component (era, modification or scenario)*/
+	struct elem {
+		elem(const std::string& _id, const std::string& _type)
+			: id(_id)
+			, type(_type)
+		{}
+
+		std::string id;
+		std::string type;
+
+		bool operator ==(const elem& e) const
+				{ return id == e.id && type == e.type; }
+
+		bool operator !=(const elem& e) const { return !(*this == e); }
+	};
+
+	/** the screen to display dialogs on */
+	CVideo& video_;
+
+	/** holds all required info about the components and their dependencies */
+	config depinfo_;
+
+	/** the id of the currently selected era */
+	std::string era_;
+
+	/** the id of the currently selected scenario */
+	std::string scenario_;
+
+	/** the ids of the currently selected modifications */
+	std::vector<std::string> mods_;
+
+	/** used by save_state() and revert() to backup/restore era_ */
+	std::string prev_era_;
+
+	/** used by save_state() and revert() to backup/restore scenario_ */
+	std::string prev_scenario_;
+
+	/** used by save_state() and revert() to backup/restore mods_ */
+	std::vector<std::string> prev_mods_;
+
+	/** saves the current values of era_, scenarios_ and mods_ */
+	void save_state();
+
+	/** restores the lastly saved values of era_, scenarios_ and mods_ */
+	void revert();
+
+	/**
+	 * Attempts to change the selected scenario.
+	 * 
+	 * @param id 	the scenario's id
+	 * @return 		true if the selection was changed; false if not
+	 */
+	bool change_scenario(const std::string& id);
+
+	/**
+	 * Attempts to change the selected era.
+	 * 
+	 * @param id 	the era's id
+	 * @return 		true if the selection was changed; false if not
+	 */
+	bool change_era(const std::string& id);
+
+	/**
+	 * Attempts to change the selected modifications.
+	 * 
+	 * @param modifications 	the list of the modifications' ids
+	 * @return 					true if the selection was changed; false if not
+	 */
+	bool change_modifications(const std::vector<std::string>& modifications);
+
+	/**
+	 * Decides if two components are conflicting or not
+	 * 
+	 * @param elem1 			the first component
+	 * @param elem2 			the second component
+	 * @param directonly 		whether the function should ignore any possible
+	 * 							conflicts between the components' dependencies.
+	 * 
+	 * @return 					true if e1 and e2 conflict, false if not
+	 */
+	bool conflicts(const elem& elem1, const elem& elem2, bool directonly=false) const;
+
+	/**
+	 * Decides whether e1 requires e2
+	 * 
+	 * @param elem1 	a component; by definition, passing a modification here
+	 * 					makes no sense
+	 * @param elem2 	another component; by definition, passing anything else
+	 * 					than a modification here makes no sense
+	 * 
+	 * @return 			true if e2 is required by e1, false if not
+	 */
+	bool requires(const elem& elem1, const elem& elem2) const;
+
+	/**
+	 * Get the list of modifications required by a certain component
+	 * 
+	 * @param e 	the component
+	 * 
+	 * @return 		the list of the modifications' ids
+	 */
+	std::vector<std::string> get_required(const elem& e) const;
+
+	/**
+	 * Get the list of modifications which are required by a certain
+	 * component, but aren't currently enabled
+	 * 
+	 * @param e 	the component
+	 * 
+	 * @return 		the list of the modifications' ids
+	 */
+	std::vector<std::string> get_required_not_enabled(const elem& e) const;
+
+	/**
+	 * Get the list of modifications which are conflicting a certain
+	 * component and are currently enabled
+	 * 
+	 * @param e 	the component
+	 * 
+	 * @return 		the list of the modifications' ids
+	 */
+	std::vector<std::string> get_conflicting_enabled(const elem& e) const;
+
+	/**
+	 * Get the list of modifications which are required by a certain
+	 * component, but currently unavailable on the computer
+	 * 
+	 * @param e 	the component
+	 * 
+	 * @return 		the list of the modifications' ids
+	 */
+	std::vector<std::string> get_required_not_installed(const elem& e) const;
+
+	/**
+	 * Display a dialog requesting confirmation for enabling some
+	 * modifications
+	 * 
+	 * @param mods 		the list of modifications to be enabled
+	 * 
+	 * @return 			true, if the user accepted the change, false if not
+	 */
+	bool enable_mods_dialog(const std::vector<std::string>& mods);
+
+	/**
+	 * Display a dialog requesting confirmation for disabling some
+	 * modifications
+	 * 
+	 * @param mods 		the list of modifications to be disabled
+	 * 
+	 * @return 			true, if the user accepted the change, false if not
+	 */
+	bool disable_mods_dialog(const std::vector<std::string>& mods);
+
+	/**
+	 * Display a dialog requesting the user to select a new era
+	 * 
+	 * @param eras 		the possible options (ids)
+	 * 
+	 * @return 			the selected era's id or empty string if the user
+	 * 					refused to select any
+	 */
+	std::string change_era_dialog(const std::vector<std::string>& eras);
+
+	/**
+	 * Display a dialog requesting the user to select a new scenario
+	 * 
+	 * @param scenarios the possible options (ids)
+	 * 
+	 * @return 			the selected scenario's id or empty string if the user
+	 * 					refused to select any
+	 */
+	std::string change_scenario_dialog
+				(const std::vector<std::string>& scenarios);
+
+	/**
+	 * Shows an error message
+	 * 
+	 * @param msg the message to be displayed
+	 */
+	void failure_dialog(const std::string& msg);
+
+	/**
+	 * Decides whether a certain component is installed or not
+	 * 
+	 * @param e 	the component
+	 * 
+	 * @return 		true if the component exists false if not
+	 */
+	bool exists(const elem& e) const;
+
+};
+
+} //namespace depcheck
+
+} //namespace mp
+
+#endif
Index: src/mp_options.cpp
===================================================================
--- src/mp_options.cpp	(revision 0)
+++ src/mp_options.cpp	(working copy)
@@ -0,0 +1,528 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#include "mp_options.hpp"
+#include "gettext.hpp"
+#include "gui/auxiliary/window_builder.hpp"
+#include "gui/dialogs/transient_message.hpp"
+#include "gui/widgets/slider.hpp"
+#include "gui/widgets/text_box.hpp"
+#include "gui/widgets/toggle_button.hpp"
+#include <boost/foreach.hpp>
+
+namespace mp
+{
+
+namespace options
+{
+
+config to_event(const config& cfg)
+{
+	config result;
+
+	if (!cfg) {
+		return result;
+	}
+
+	result["name"] = "prestart";
+
+	BOOST_FOREACH (const config& c, cfg.child_range("option")) {
+		config ev;
+		ev["name"] = c["id"];
+		ev["value"] = c["value"];
+		result.add_child("set_variable", ev);
+	}
+
+	return result;
+}
+
+void manager::init_info(const config& cfg, const std::string& key)
+{
+	BOOST_FOREACH (const config& comp, cfg.child_range(key)) {
+		config entry;
+		entry["id"] = comp["id"];
+		entry["name"] = comp["name"];
+		
+		if (comp.has_child("options")) {
+			const config& options = comp.child("options");
+
+			BOOST_FOREACH (const config::any_child& c,
+								options.all_children_range()) {
+				entry.add_child(c.key, c.cfg);
+			}
+
+		}
+
+		// We need to store components even if they don't have any options in
+		// order to have set_xxx_by_index work properly
+		options_info_.add_child(key, entry);
+	}
+}
+
+manager::manager(const config& gamecfg, CVideo& video, const config& values)
+		: options_info_()
+		, values_(values)
+		, video_(video)
+		, era_()
+		, scenario_()
+		, modifications_()
+{
+	init_info(gamecfg, "modification");
+	init_info(gamecfg, "era");
+	init_info(gamecfg, "multiplayer");
+
+	BOOST_FOREACH (const config::any_child& i,
+				   options_info_.all_children_range())
+	{
+		BOOST_FOREACH (const config::any_child& j, i.cfg.all_children_range())
+		{
+			if (is_valid_option(j.key, j.cfg)) {
+				config& value = get_value_cfg(j.cfg["id"]);
+				value["value"] = get_stored_value(j.cfg["id"]);
+			}
+		}
+	}
+}
+
+
+void manager::set_values(const config& c)
+{
+	values_ = c;
+}
+
+void manager::set_era(const std::string& era)
+{
+	era_ = era;
+}
+
+void manager::set_era_by_index(int index)
+{
+	era_ = options_info_.child("era", index)["id"].str();
+}
+
+void manager::set_scenario(const std::string& scenario)
+{
+	scenario_ = scenario;
+}
+
+void manager::set_scenario_by_index(int index)
+{
+	scenario_ = options_info_.child("multiplayer", index - 1)["id"].str();
+}
+
+void manager::set_modifications(const std::vector<std::string>& modifications)
+{
+	modifications_ = modifications;
+}
+
+void manager::insert_element(elem_type type, const config& data, int pos)
+{
+	switch (type)
+	{
+	case SCENARIO:
+		options_info_.add_child_at("multiplayer", data, pos);
+		break;
+	case ERA:
+		options_info_.add_child_at("era", data, pos);
+		break;
+	case MODIFICATION:
+		options_info_.add_child_at("modification", data, pos);
+		break;
+	}
+}
+
+void manager::show_dialog()
+{
+	config dialog_cfg;
+
+	dialog_cfg.add_child("resolution");
+	dialog_cfg["definition"] = "default";
+	dialog_cfg["automatic_placement"] = true;
+	dialog_cfg["vertical_placement"] = "center";
+	dialog_cfg["horizontal_placement"] = "center";
+	dialog_cfg.add_child("helptip")["id"] = "tooltip_large";
+	dialog_cfg.add_child("tooltip")["id"] = "tooltip_large";
+
+	config& grid = dialog_cfg.add_child("grid");
+	
+	add_widgets(options_info_.find_child("era", "id", era_), grid);
+	add_widgets(options_info_.find_child("multiplayer", "id", scenario_), grid);
+
+	for (unsigned i = 0; i<modifications_.size(); i++) {
+		add_widgets(
+			options_info_.find_child("modification", "id", modifications_[i]),
+			grid);
+	}
+
+	if (grid.ordered_begin() == grid.ordered_end()) {
+		// No widgets were actually added, we've got nothing to show
+		gui2::show_transient_message(video_, "", _(
+				"None of the selected modifications, era or scenario provide " \
+				"configuration options."));
+		
+		return;
+	}
+
+	config& row = grid.add_child("row");
+	row["grow_factor"] = 0;
+
+	config& column = row.add_child("column");
+	column["grow_factor"] = 1;
+	column["border"] = "all";
+	column["border_size"] = 5;
+	column["horizontal_alignment"] = "right";
+
+	config& widget_grid = column.add_child("grid");
+
+	config& widget_row = widget_grid.add_child("row");
+	widget_row["grow_factor"] = 0;
+
+	config& ok_column = widget_row.add_child("column");
+	ok_column["grow_factor"] = 1;
+	ok_column["border"] = "all";
+	ok_column["border_size"] = 5;
+	ok_column["horizontal_alignment"] = "right";
+
+	config& cancel_column = widget_row.add_child("column");
+	cancel_column["grow_factor"] = 0;
+	cancel_column["border"] = "all";
+	cancel_column["border_size"] = 5;
+	cancel_column["horizontal_alignment"] = "left";
+
+	config& ok_button = ok_column.add_child("button");
+	ok_button["definition"] = "default";
+	ok_button["label"] = _("OK");
+	ok_button["id"] = "ok";
+
+	config& cancel_button = cancel_column.add_child("button");
+	cancel_button["definition"] = "default";
+	cancel_button["label"] = _("Cancel");
+	cancel_button["id"] = "cancel";
+
+	gui2::twindow_builder::tresolution resolution(dialog_cfg);
+	gui2::twindow* window = gui2::build(video_, &resolution);
+
+	__tmp_set_checkbox_defaults(window);
+
+	if (window->show() == gui2::twindow::CANCEL) {
+		delete window;
+		
+		return;
+	}
+
+	write_values("era", era_, window);
+	write_values("multiplayer", scenario_, window);
+	for (unsigned i = 0; i<modifications_.size(); i++) {
+		write_values("modification", modifications_[i], window);
+	}
+
+	delete window;
+}
+
+void manager::add_widgets(const config& data, config& grid) const
+{
+	if (!data.has_child("entry") &&
+		!data.has_child("slider") &&
+		!data.has_child("checkbox"))
+	{
+		//Don't display the title if there're no options at all
+		return;
+	}
+
+	{
+		config& row = grid.add_child("row");
+		row["grow_factor"] = 0;
+		config& column = row.add_child("column");
+		column["grow_factor"] = 1;
+		column["border"] = "all";
+		column["border_size"] = 5;
+		column["horizontal_alignment"] = "left";
+		config& caption = column.add_child("label");
+		caption["definition"] = "title";
+		caption["label"] = data["name"];
+	}
+	
+	BOOST_FOREACH (const config::any_child& c, data.all_children_range()) {
+		if (!is_valid_option(c.key, c.cfg))
+		{
+			continue;
+		}
+		
+		config& row = grid.add_child("row");
+		row["grow_factor"] = 0;
+		config& column = row.add_child("column");
+		column["grow_factor"] = 1;
+		column["border"] = "all";
+		column["border_size"] = 5;
+		column["horizontal_alignment"] = "left";
+
+		if (c.key == "entry") {
+			add_entry(c.cfg, column);
+		} else if (c.key == "slider") {
+			add_slider(c.cfg, column);
+		} else if (c.key == "checkbox") {
+			add_checkbox(c.cfg, column);
+		}
+	}
+}
+
+void manager::add_entry(const config& data, config& column) const
+{
+	config& grid = column.add_child("grid");
+	config& row = grid.add_child("row");
+	row["grow_factor"] = 0;
+
+	config& label_column = row.add_child("column");
+	label_column["grow_factor"] = 0;
+	label_column["border"] = "all";
+	label_column["border_size"] = 5;
+	label_column["horizontal_alignment"] = "left";
+
+	config& entry_column = row.add_child("column");
+	entry_column["grow_factor"] = 0;
+	entry_column["border"] = "all";
+	entry_column["border_size"] = 5;
+	entry_column["horizontal_alignment"] = "left";
+
+	config& label = label_column.add_child("label");
+	label["definition"] = "default";
+	label["label"] = data["description"];
+
+	config& entry = entry_column.add_child("text_box");
+	entry["id"] = data["id"];
+	entry["definition"] = "default";
+	entry["label"] = get_stored_value(data["id"]);
+}
+
+void manager::add_slider(const config& data, config& column) const
+{
+	config& grid = column.add_child("grid");
+	config& row = grid.add_child("row");
+	row["grow_factor"] = 0;
+
+	config& label_column = row.add_child("column");
+	label_column["grow_factor"] = 0;
+	label_column["border"] = "all";
+	label_column["border_size"] = 5;
+	label_column["horizontal_alignment"] = "left";
+
+	config& slider_column = row.add_child("column");
+	slider_column["grow_factor"] = 0;
+	slider_column["border"] = "all";
+	slider_column["border_size"] = 5;
+	slider_column["horizontal_alignment"] = "left";
+
+	config& label = label_column.add_child("label");
+	label["definition"] = "default";
+	label["label"] = data["description"];
+
+	config& slider = slider_column.add_child("slider");
+	slider["id"] = data["id"];
+	slider["definition"] = "default";
+	slider["minimum_value"] = data["min_value"];
+	slider["maximum_value"] = data["max_value"];
+	slider["step_size"] = data["step"].to_int() ? data["step"].to_int() : 1;
+
+	slider["value"] = get_stored_value(data["id"]);
+}
+
+void manager::add_checkbox(const config& data, config& column) const
+{
+	config& grid = column.add_child("grid");
+	config& row = grid.add_child("row");
+	row["grow_factor"] = 0;
+
+	config& box_column = row.add_child("column");
+	box_column["grow_factor"] = 0;
+	box_column["border"] = "all";
+	box_column["border_size"] = 5;
+	box_column["horizontal_alignment"] = "left";
+
+	config& checkbox = box_column.add_child("toggle_button");
+	checkbox["id"] = data["id"];
+	checkbox["definition"] = "default";
+	checkbox["label"] = data["description"];
+}
+
+config& manager::get_value_cfg(const std::string& id)
+{
+	{
+		const manager* m = this;
+		config& value_cfg = const_cast<config&>(m->get_value_cfg(id));
+		if (!value_cfg.empty()) {
+			return value_cfg;
+		}
+	}
+
+	config::any_child info = get_option_parent(id);
+	config* parent_cfg;
+	if (!values_.find_child(info.key, "id", info.cfg["id"])) {
+		parent_cfg = &values_.add_child(info.key);
+		(*parent_cfg)["id"] = info.cfg["id"];
+	} else {
+		parent_cfg = &values_.find_child(info.key, "id", info.cfg["id"]);
+	}
+
+	config& value_cfg = parent_cfg->add_child("option");
+	value_cfg["id"] = id;
+
+	return value_cfg;
+}
+
+const config& manager::get_value_cfg(const std::string& id) const
+{
+	static const config empty;
+	
+	BOOST_FOREACH (const config::any_child& i, values_.all_children_range()) {
+		BOOST_FOREACH (const config& j, i.cfg.child_range("option")) {
+			if (j["id"] == id) {
+				return j;
+			}
+		}
+	}
+
+	return empty;
+}
+
+config::any_child manager::get_option_parent(const std::string& id) const
+{
+	static const config empty;
+	static const std::string empty_key = "";
+	static config::any_child not_found(&empty_key, &empty);
+	
+	BOOST_FOREACH (const config::any_child& i,
+				   options_info_.all_children_range()) {
+		BOOST_FOREACH (const config::any_child& j, i.cfg.all_children_range()) {
+			if (j.cfg["id"] == id) {
+				return i;
+			}
+		}
+	}
+
+	return not_found;
+}
+
+const config& manager::get_option_info_cfg(const std::string& id) const
+{
+	static const config empty;
+
+	BOOST_FOREACH (const config::any_child& i,
+				   options_info_.all_children_range()) {
+		BOOST_FOREACH (const config::any_child& j, i.cfg.all_children_range()) {
+			if (j.cfg["id"] == id) {
+				return j.cfg;
+			}
+		}
+	}
+
+	return empty;
+}
+
+
+config::attribute_value manager::get_stored_value(const std::string& id) const
+{
+	const config& valcfg = get_value_cfg(id);
+
+	if (!valcfg["value"].empty()) {
+		// There's a saved value for this option
+		return valcfg["value"];
+	}
+
+	// Fall back to the option's default
+	const config& optinfo = get_option_info_cfg(id);
+
+	return optinfo["default"];
+}
+
+int manager::get_slider_value(const std::string& id, gui2::twindow* win) const
+{
+	gui2::tslider* widget =
+						gui2::find_widget<gui2::tslider>(win, id, false, true);
+
+	return widget->get_value();
+}
+
+bool manager::get_checkbox_value
+					(const std::string& id, gui2::twindow* win) const
+{
+	gui2::ttoggle_button* widget =
+				gui2::find_widget<gui2::ttoggle_button>(win, id, false, true);
+
+	return widget->get_value();
+}
+
+std::string manager::get_entry_value(const std::string& id,
+									 gui2::twindow* window) const
+{
+	gui2::ttext_box* widget =
+				gui2::find_widget<gui2::ttext_box>(window, id, false, true);
+
+	return widget->text();
+}
+
+void manager::write_values(const std::string& key, const std::string& id,
+						   gui2::twindow* window)
+{
+	BOOST_FOREACH (const config::any_child& c,
+				   options_info_.find_child(key, "id", id).all_children_range())
+	{
+		if (!is_valid_option(c.key, c.cfg)) {
+			continue;
+		}
+		
+		config& out = get_value_cfg(c.cfg["id"].str());
+
+		if (c.key == "entry") {
+			out["value"] = get_entry_value(c.cfg["id"], window);
+		} else if (c.key == "slider") {
+			out["value"] = get_slider_value(c.cfg["id"], window);
+		} else if (c.key == "checkbox") {
+			out["value"] = get_checkbox_value(c.cfg["id"], window);
+		}
+	}
+}
+
+bool manager::is_valid_option(const std::string& key,
+							  const config& option) const
+{
+	return (key == "slider" || key == "entry" || key == "checkbox") &&
+		   (!option["id"].empty());
+}
+
+void manager::__tmp_set_checkbox_defaults(gui2::twindow* window) const
+{
+	BOOST_FOREACH (const config::any_child& i,
+				   options_info_.all_children_range())
+	{
+		BOOST_FOREACH (const config& j, i.cfg.child_range("checkbox"))
+		{
+			if (!is_valid_option("checkbox", j)) {
+				continue;
+			}
+			
+			gui2::ttoggle_button* button;
+			button = gui2::find_widget<gui2::ttoggle_button>
+										(window, j["id"].str(), false, false);
+
+			if (button) {
+				button->set_value(get_stored_value(j["id"]).to_bool());
+			}
+		}
+	}
+}
+
+}	// namespace options
+
+}	// namespace mp
+
Index: src/multiplayer_create.cpp
===================================================================
--- src/multiplayer_create.cpp	(revision 54884)
+++ src/multiplayer_create.cpp	(working copy)
@@ -30,6 +30,7 @@
 #include "map_exception.hpp"
 #include "map_create.hpp"
 #include "gui/dialogs/message.hpp"
+#include "gui/dialogs/mp_create_game_choose_mods.hpp"
 #include "gui/dialogs/mp_create_game_set_password.hpp"
 #include "gui/dialogs/transient_message.hpp"
 #include "minimap.hpp"
@@ -59,11 +60,13 @@
 
 	local_players_only_(local_players_only),
 	tooltip_manager_(disp.video()),
+	era_selection_(-1),
 	map_selection_(-1),
 	mp_countdown_init_time_(270),
 	mp_countdown_reservoir_time_(330),
 	user_maps_(),
 	map_options_(),
+	available_mods_(),
 	map_index_(),
 
 	maps_menu_(disp.video(), std::vector<std::string>()),
@@ -95,11 +98,13 @@
 	shroud_game_(disp.video(), _("Shroud"), gui::button::TYPE_CHECK),
 	observers_game_(disp.video(), _("Observers"), gui::button::TYPE_CHECK),
 	shuffle_sides_(disp.video(), _("Shuffle sides"), gui::button::TYPE_CHECK),
+	options_(disp.video(), _("Options...")),
 	cancel_game_(disp.video(), _("Cancel")),
 	launch_game_(disp.video(), _("OK")),
 	regenerate_map_(disp.video(), _("Regenerate")),
 	generator_settings_(disp.video(), _("Settings...")),
 	password_button_(disp.video(), _("Set Password...")),
+	choose_mods_(disp.video(), _("Modifications...")),
 	era_combo_(disp, std::vector<std::string>()),
 	vision_combo_(disp, std::vector<std::string>()),
 	name_entry_(disp.video(), 32),
@@ -107,7 +112,9 @@
 	minimap_rect_(null_rect),
 	generator_(NULL),
 	num_turns_(0),
-	parameters_()
+	parameters_(),
+	dependency_manager_(cfg, disp.video()),
+	options_manager_(cfg, disp.video(), preferences::options())
 {
 	// Build the list of scenarios to play
 
@@ -128,6 +135,22 @@
 	{
 		menu_help_str = help_sep + user_maps_[i];
 		map_options_.push_back(user_maps_[i] + menu_help_str);
+
+		// Since user maps are treated as scenarios,
+		// some dependency info is required
+		config depinfo;
+
+		depinfo["id"] = user_maps_[i];
+		depinfo["name"] = user_maps_[i];
+
+		dependency_manager_.insert_element(depcheck::SCENARIO, depinfo, i);
+
+		// Same with options
+		// FIXME: options::elem_type duplicates depcheck::component_type
+		//        Perhaps they should me merged?
+		config optinfo = depinfo;
+
+		options_manager_.insert_element(options::SCENARIO, optinfo, i);
 	}
 
 	// Standard maps
@@ -146,8 +169,11 @@
 
 	// Create the scenarios menu
 	maps_menu_.set_items(map_options_);
-	if (size_t(preferences::map()) < map_options_.size())
+	if (size_t(preferences::map()) < map_options_.size()) {
 		maps_menu_.move_selection(preferences::map());
+		dependency_manager_.try_scenario_by_index(preferences::map(), true);
+		options_manager_.set_scenario_by_index(preferences::map());
+	}
 	maps_menu_.set_numeric_keypress_selection(false);
 
 	turns_slider_.set_min(settings::turns_min);
@@ -239,10 +265,26 @@
 	if (size_t(preferences::era()) < eras.size()) {
 		era_combo_.set_selected(preferences::era());
 	} else {
-		era_combo_.set_selected(0);
+		era_combo_.set_selected(preferences::era());
 	}
 
+	dependency_manager_.try_era_by_index(era_selection_, true);
+	options_manager_.set_era_by_index(era_selection_);
 
+	// Available modifications
+	BOOST_FOREACH (const config& mod, cfg.child_range("modification")) {
+		available_mods_.add_child("modification", mod);
+	}
+
+	BOOST_FOREACH (const std::string& str, preferences::modifications()) {
+		if (cfg.find_child("modification", "id", str))
+			parameters_.active_mods.push_back(str);
+	}
+
+	dependency_manager_.try_modifications(parameters_.active_mods, true);
+	options_manager_.set_modifications(parameters_.active_mods);
+
+
 	utils::string_map i18n_symbols;
 	i18n_symbols["login"] = preferences::login();
 	name_entry_.set_text(vgettext("$login|’s game", i18n_symbols));
@@ -272,8 +314,10 @@
 	preferences::set_countdown_turn_bonus(parameters_.mp_countdown_turn_bonus);
 	preferences::set_countdown_reservoir_time(parameters_.mp_countdown_reservoir_time);
 	preferences::set_countdown_action_bonus(parameters_.mp_countdown_action_bonus);
-	preferences::set_era(era_combo_.selected()); /** @todo FIXME: may be broken if new eras are added. */
+	preferences::set_era(era_selection_); /** @todo FIXME: may be broken if new eras are added. */
 	preferences::set_map(map_selection_);
+	preferences::set_modifications(parameters_.active_mods);
+	preferences::set_options(parameters_.options);
 
 	// When using map settings, the following variables are determined by the map,
 	// so don't store them as the new preferences.
@@ -335,6 +379,7 @@
 	parameters_.shuffle_sides = shuffle_sides_.checked();
 	parameters_.share_view = vision_combo_.selected() == 0;
 	parameters_.share_maps = vision_combo_.selected() == 1;
+	parameters_.options = options_manager_.get_values();
 
 	return parameters_;
 }
@@ -369,12 +414,35 @@
 		}
 	}
 
+	if(options_.pressed()) {
+		options_manager_.show_dialog();
+	}
+
 	if(password_button_.pressed()) {
 		gui2::tmp_create_game_set_password::execute(
 				  parameters_.password
 				, disp_.video());
 	}
 
+	if(choose_mods_.pressed()) {
+		if (available_mods_.empty()) {
+			gui2::show_transient_message(disp_.video(), "",
+			_(	"There are no modifications currently installed." \
+				" To download modifications, connect to the add-ons server" \
+				" by choosing the 'Add-ons' option on the main screen."		));
+		} else {
+
+			gui2::tmp_create_game_choose_mods
+						dialog(available_mods_, parameters_.active_mods);
+
+			dialog.show(disp_.video());
+
+			dependency_manager_.try_modifications(parameters_.active_mods);
+			options_manager_.set_modifications(parameters_.active_mods);
+			synchronize_selections();
+		}
+	}
+
 	// Turns per game
 	const int cur_turns = turns_slider_.value();
 
@@ -447,9 +515,24 @@
 
 	xp_modifier_label_.set_text(buf.str());
 
+	bool era_changed = era_selection_ != era_combo_.selected();
+	era_selection_ = era_combo_.selected();
+
+	if (era_changed) {
+		dependency_manager_.try_era_by_index(era_selection_);
+		options_manager_.set_era_by_index(era_selection_);
+		synchronize_selections();
+	}
+
 	bool map_changed = map_selection_ != maps_menu_.selection();
 	map_selection_ = maps_menu_.selection();
 
+	if (map_changed) {
+		dependency_manager_.try_scenario_by_index(map_selection_);
+		options_manager_.set_scenario_by_index(map_selection_);
+		synchronize_selections();
+	}
+
 	if(map_changed) {
 		generator_.assign(NULL);
 
@@ -776,6 +859,8 @@
 	ypos += era_label_.height() + border_size;
 	era_combo_.set_location(xpos, ypos);
 	ypos += era_combo_.height() + border_size;
+	choose_mods_.set_location(xpos, ypos);
+	ypos += choose_mods_.height() + border_size;
 	if(!local_players_only_) {
 		password_button_.set_location(xpos, ypos);
 		ypos += password_button_.height() + border_size;
@@ -876,7 +961,28 @@
 	                           ca.y + ca.h - right_button->height());
 	left_button->set_location(right_button->location().x - left_button->width() -
 	                          gui::ButtonHPadding, ca.y + ca.h - left_button->height());
+
+	options_.set_location(left_button->location().x - options_.width() -
+					gui::ButtonHPadding, ca.y + ca.h - options_.height());
 }
 
+void create::synchronize_selections()
+{
+	if (era_selection_ != dependency_manager_.get_era_index()) {
+		era_combo_.set_selected(dependency_manager_.get_era_index());
+		process_event();
+	}
+
+	if (map_selection_ != dependency_manager_.get_scenario_index()) {
+		maps_menu_.move_selection(dependency_manager_.get_scenario_index());
+		process_event();
+	}
+
+	parameters_.active_mods = dependency_manager_.get_modifications();
+	options_manager_.set_modifications(dependency_manager_.get_modifications());
+	options_manager_.set_era(dependency_manager_.get_era());
+	options_manager_.set_scenario(dependency_manager_.get_scenario());
+}
+
 } // namespace mp
 
Index: src/game_preferences.cpp
===================================================================
--- src/game_preferences.cpp	(revision 54884)
+++ src/game_preferences.cpp	(working copy)
@@ -53,6 +53,12 @@
 bool friends_initialized = false;
 bool ignores_initialized = false;
 
+std::vector<std::string> mp_modifications;
+bool modifications_initialized = false;
+
+config option_values;
+bool options_initialized = false;
+
 bool authenticated = false;
 
 const char WRAP_CHAR = '@';
@@ -77,10 +83,17 @@
 	return raw.substr(1, raw.length() - 2);
 }
 
+void initialize_modifications()
+{
+	mp_modifications = utils::split(preferences::get("modifications"), ',');
+	modifications_initialized = true;
+}
+
 } // anon namespace
 
 namespace preferences {
 
+
 manager::manager() :
 	base()
 {
@@ -580,6 +593,32 @@
 	preferences::set("mp_turns", value);
 }
 
+const config& options()
+{
+	if (options_initialized) {
+		return option_values;
+	}
+
+	if (!preferences::get_child("options")) {
+		// It may be an invalid config, which would cause problems in
+		// multiplayer_create, so let's replace it with an empty but valid
+		// config
+		option_values = config();
+	} else {
+		option_values = preferences::get_child("options");
+	}
+	
+	options_initialized = true;
+
+	return option_values;
+}
+
+void set_options(const config& values)
+{
+	preferences::set_child("options", values);
+	options_initialized = false;
+}
+
 bool skip_mp_replay()
 {
 	return preferences::get("skip_mp_replay", false);
@@ -694,6 +733,20 @@
 	preferences::set("mp_map", value);
 }
 
+const std::vector<std::string>& modifications()
+{
+	if (!modifications_initialized)
+		initialize_modifications();
+
+	return mp_modifications;
+}
+
+void set_modifications(const std::vector<std::string>& value)
+{
+	preferences::set("modifications", utils::join(value, ","));
+	modifications_initialized = false;
+}
+
 bool show_ai_moves()
 {
 	return preferences::get("show_ai_moves", true);
Index: src/server/simple_wml.hpp
===================================================================
--- src/server/simple_wml.hpp	(revision 54884)
+++ src/server/simple_wml.hpp	(working copy)
@@ -242,6 +242,10 @@
 		return root().child(name);
 	}
 
+	const node::child_list& children(const char* name) const {
+		return root().children(name);
+	}
+
 	node& set_attr(const char* key, const char* value) {
 		return root().set_attr(key, value);
 	}
Index: src/server/server.cpp
===================================================================
--- src/server/server.cpp	(revision 54884)
+++ src/server/server.cpp	(working copy)
@@ -2401,6 +2401,7 @@
 				rooms_.lobby().send_server_message("The scenario data is missing the [multiplayer] tag which contains the game settings. Game aborted.", sock);
 				return;
 			}
+
 			g->set_description(&desc);
 			desc.set_attr_dup("id", lexical_cast<std::string>(g->id()).c_str());
 		} else {
@@ -2425,6 +2426,14 @@
 			}
 		}
 
+		const simple_wml::node::child_list& mlist = data.children("modification");
+		BOOST_FOREACH (const simple_wml::node* m, mlist) {
+			desc.add_child_at("modification", 0);
+			desc.child("modification")->set_attr_dup("id", m->attr("id"));
+			if (m->attr("require_modification").to_bool(false))
+				desc.child("modification")->set_attr("require_modification", "yes");
+		}
+
 		// Record the full scenario in g->level()
 		g->level().swap(data);
 		// The host already put himself in the scenario so we just need
@@ -2494,6 +2503,7 @@
 			rooms_.lobby().send_server_message("The scenario data is missing the [multiplayer] tag which contains the game settings. Game aborted.", sock);
 			return;
 		}
+
 		// If there is no shroud, then tell players in the lobby
 		// what the map looks like.
 		const simple_wml::node& s = g->level().root();
Index: src/CMakeLists.txt
===================================================================
--- src/CMakeLists.txt	(revision 54884)
+++ src/CMakeLists.txt	(working copy)
@@ -716,7 +716,10 @@
 	gui/dialogs/mp_cmd_wrapper.cpp
 	gui/dialogs/mp_connect.cpp
 	gui/dialogs/mp_create_game.cpp
+	gui/dialogs/mp_create_game_choose_mods.cpp
 	gui/dialogs/mp_create_game_set_password.cpp
+	gui/dialogs/mp_depcheck_confirm_change.cpp
+	gui/dialogs/mp_depcheck_select_new.cpp
 	gui/dialogs/mp_host_game_prompt.cpp
 	gui/dialogs/mp_login.cpp
 	gui/dialogs/mp_method_selection.cpp
@@ -737,7 +740,9 @@
 	menu_events.cpp
 	mouse_events.cpp
 	mouse_handler_base.cpp
+	mp_depcheck.cpp
 	mp_game_settings.cpp
+	mp_options.cpp
 	multiplayer.cpp
 	multiplayer_connect.cpp
 	multiplayer_create.cpp
Index: src/mp_game_settings.hpp
===================================================================
--- src/mp_game_settings.hpp	(revision 54884)
+++ src/mp_game_settings.hpp	(working copy)
@@ -39,6 +39,7 @@
 	std::string hash;
 	std::string mp_era;
 	std::string mp_scenario;
+	std::vector<std::string> active_mods;
 
 	int village_gold;
 	int village_support;
@@ -59,6 +60,8 @@
 
 	bool saved_game;
 
+	config options;
+
 	/**
 	 * If the game is to be randomly generated, the map generator
 	 * will create the scenario data in this variable
Index: src/scripting/lua.cpp
===================================================================
--- src/scripting/lua.cpp	(revision 54884)
+++ src/scripting/lua.cpp	(working copy)
@@ -3881,9 +3881,9 @@
 
 static char const *handled_file_tags[] = {
 	"color_palette", "color_range", "era", "event", "generator",
-	"label", "lua", "map", "menu_item", "music", "side", "sound_source", "story",
-	"terrain_graphics", "time", "time_area", "tunnel", "variables", "endlevel",
-	"display",
+	"label", "lua", "map", "menu_item", "modification", "music", "options",
+	"side", "sound_source", "story","terrain_graphics", "time", "time_area",
+	"tunnel", "variables", "endlevel", "display",
 	//TODO: These are only needed for MP campaigns and only for subsequent scenarios, see bug #18883
 	"snapshot", "multiplayer", "replay_start"
 };
Index: src/mp_options.hpp
===================================================================
--- src/mp_options.hpp	(revision 0)
+++ src/mp_options.hpp	(working copy)
@@ -0,0 +1,327 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#ifndef MP_OPTIONS_HPP_INCLUDED
+#define MP_OPTIONS_HPP_INCLUDED
+
+#include <string>
+#include <map>
+#include "config.hpp"
+#include "video.hpp"
+#include "gui/widgets/widget.hpp"
+#include "gui/widgets/window.hpp"
+
+namespace mp
+{
+
+namespace options
+{
+
+config to_event(const config& options);
+
+enum elem_type
+{
+	SCENARIO,
+	ERA,
+	MODIFICATION
+};
+
+class manager
+{
+public:
+
+	/**
+	 * Constructor.
+	 *
+	 * @param gamecfg			The config object holding all eras, scenarios
+	 * 							and modifications.
+	 *
+	 * @param video				The screen to display the dialog on.
+	 *
+	 * @param initial_values	The initial values for each option.
+	 */
+	manager(const config& gamecfg, CVideo& video, const config& initial_values);
+
+	/**
+	 * Set the current values the options. This overrides ALL previously set
+	 * values, even if a not all options are provided a new value for.
+	 *
+	 * @param values			The new values for each option.
+	 */
+	void set_values(const config& values);
+
+	/**
+	 * Sets the selected era. Whenever show_dialog is called, only
+	 * options for the selected era will be displayed.
+	 *
+	 * @param id				The era's id.
+	 */
+	void set_era(const std::string& id);
+
+	/**
+	 * Sets the selected era. Whenever show_dialog is called, only
+	 * options for the selected era will be displayed.
+	 *
+	 * @param index				The era's index.
+	 */
+	void set_era_by_index(int index);
+
+	/**
+	 * Sets the selected scenario. Whenever show_dialog is called, only
+	 * options for the selected scenario will be displayed.
+	 *
+	 * @param id 				The scenario's id.
+	 */
+	void set_scenario(const std::string& id);
+
+	/**
+	 * Sets the selected scenario. Whenever show_dialog is called, only
+	 * options for the selected scenario will be displayed.
+	 *
+	 * @param index 				The scenario's index.
+	 */
+	void set_scenario_by_index(int index);
+
+	/**
+	 * Sets the activated modifications. Whenever show_dialog is called, only
+	 * options for the activated modifications will be displayed.
+	 *
+	 * @param ids					The ids of the modifications
+	 */
+	void set_modifications(const std::vector<std::string>& ids);
+
+	/**
+	 * Add options information of an era/scenario/modification not yet in the
+	 * database.
+	 *
+	 * @param type					The type of the element,
+	 * 
+	 * @param data					The config object which holds the
+	 * 								information about the element's options in
+	 * 								an [options] child.
+	 * 
+	 * @param pos					The position to insert  the element into.
+	 */
+	void insert_element(elem_type type, const config& data, int pos);
+
+	/**
+	 * Shows the options dialog and saves the selected values.
+	 */
+	void show_dialog();
+
+	/**
+	 * Returns the the values for each option.
+	 *
+	 * @return						A config containing the values.
+	 */
+	const config& get_values() const { return values_; }
+
+private:
+	/** Stores needed info about each element and their configuration options */
+	config options_info_;
+
+	/** Stores the selected values for each option */
+	config values_;
+
+	/** The screen to display the dialog on */
+	CVideo &video_;
+
+	/** The id of the selected era */
+	std::string era_;
+
+	/** The id of the selected scenario */
+	std::string scenario_;
+
+	/** The ids of the selected modifications */
+	std::vector<std::string> modifications_;
+
+	/**
+	 * Adds the necessary information about the specified component
+	 * to options_info_.
+	 *
+	 * @param cfg 					The component's data.
+	 * @param key					The component's type.
+	 */
+	void init_info(const config& cfg, const std::string& key);
+
+	/**
+	 * Creates a widget layout based on an [options] section.
+	 *
+	 * @param data					The [options] section.
+	 * @param grid					The grid to create the layout in.
+	 */
+	void add_widgets(const config& data, config& grid) const;
+
+	/**
+	 * Creates a slider widget.
+	 *
+	 * @param data					A [slider] config.
+	 * @param column				The grid cell to add the widget into.
+	 */
+	void add_slider(const config& data, config& column) const;
+
+	/**
+	 * Creates a checkbox (toggle button) widget.
+	 *
+	 * @param data					A [checkbox] config.
+	 * @param column				The grid cell to add the widget into.
+	 */
+	void add_checkbox(const config& data, config& column) const;
+
+	/**
+	 * @todo Implement this function (along with a combo box widget, preferably)
+	 * 
+	 * Creates a combo box widget.
+	 *
+	 * @param data					A [combobox] config.
+	 * @param column				The grid cell to add the widget into.
+	 */
+	void add_combobox(const config& data, config& column) const;
+
+	/**
+	 * Creates a text entry widget.
+	 *
+	 * @param data					An [entry] config.
+	 * @param column				The grid cell to add the widget into.
+	 */
+	void add_entry(const config& data, config& column) const;
+
+	/**
+	 * Returns the node which holds the selected value of an option. If that
+	 * node is not yet created, the function creates it.
+	 *
+	 * @param id					The id of the option.
+	 *
+	 * @return						A reference to the config which the value
+	 * 								for this option should be written into.
+	 */
+	config& get_value_cfg(const std::string& id);
+
+	/**
+	 * Returns the node which holds the selected value of an option. If that
+	 * node is not yet created, the function returns an empty config.
+	 *
+	 * @param id					The id of the option.
+	 *
+	 * @return						A reference to the config which the value
+	 * 								for this option should be written into or
+	 * 								an empty config if that doesn't exist.
+	 */
+	const config& get_value_cfg(const std::string& id) const;
+
+	/**
+	 * Returns the information about an option.
+	 *
+	 * @param id					The id of the option.
+	 *
+	 * @return						The config object which contains the
+	 * 								settings of the option, or an empty config
+	 * 								if the option was not found.
+	 */
+	const config& get_option_info_cfg(const std::string& id) const;
+
+	/**
+	 * Finds the parent node of an options.
+	 *
+	 * @param id					The id of the option.
+	 *
+	 * @return						A config::any_child object containing the
+	 * 								key and the data of the parent node, or ""
+	 * 								for the key and an empty config if the
+	 * 								option was not found.
+	 */
+	config::any_child get_option_parent(const std::string& id) const;
+
+	/**
+	 * Retrieves the saved value for a certain option.
+	 *
+	 * @param id					The id of the option.
+	 *
+	 * @return 						The value saved in values_ for this option
+	 * 								or its specified default value if a saved
+	 * 								value can't be found.
+	 */
+	config::attribute_value get_stored_value(const std::string& id) const;
+
+	/**
+	 * Gets the current value of a slider widget.
+	 *
+	 * @param id					The id of the widget.
+	 * @param win					The window to find the widget in.
+	 *
+	 * @return						The integer currently set on the slider.
+	 */
+	int get_slider_value(const std::string& id, gui2::twindow* win) const;
+
+	/**
+	 * Gets the current value of a checkbox widget.
+	 *
+	 * @param id					The id of the widget.
+	 * @param win					The window to find the widget in.
+	 *
+	 * @return						True if the box is checked, false if not.
+	 */
+	bool get_checkbox_value(const std::string& id, gui2::twindow* win) const;
+
+	/**
+	 * Gets the current value of a text_box widget.
+	 *
+	 * @param id					The id of the widget.
+	 * @param win					The window to find the widget in.
+	 *
+	 * @return						The text written in the widget.
+	 */
+	std::string get_entry_value(const std::string& id,
+								gui2::twindow* win) const;
+
+	/**
+	 * Writes all the values for the options of a certain component from a
+	 * specified window into values_.
+	 *
+	 * @param key					The component's type.
+	 * @param id					The component's id.
+	 * @param window				The window.
+	 */
+	void write_values(const std::string& key, const std::string& id,
+					  gui2::twindow* window);
+
+	/**
+	 * Decides whether a config is a sane option node or not.
+	 * A valid option node:
+	 * 		- Must have an id field.
+	 * 		- Its key must be "slider", "entry" or "checkbox"
+	 *
+	 * @param key					The option's key.
+	 * @param option				The option's data.
+	 *
+	 * @return						True if the option is valid, false if not.
+	 */
+	bool is_valid_option(const std::string& key, const config& option) const;
+
+	/**
+	 * @todo 		Implement a way to initialize the checkbox via WML and then
+	 * 				remove this function altogether.
+	 * 
+	 * Sets the default states for all checkbox widgets inside a window. All
+	 * required data is fetched from values_ and options_info_.
+	 *
+	 * @param window				The window.
+	 */
+	void __tmp_set_checkbox_defaults(gui2::twindow* window) const;
+};
+
+} // namespace options
+
+} // namespace mp
+#endif
Index: src/multiplayer_create.hpp
===================================================================
--- src/multiplayer_create.hpp	(revision 54884)
+++ src/multiplayer_create.hpp	(working copy)
@@ -18,7 +18,9 @@
 #ifndef MULTIPLAYER_CREATE_HPP_INCLUDED
 #define MULTIPLAYER_CREATE_HPP_INCLUDED
 
+#include "mp_depcheck.hpp"
 #include "mp_game_settings.hpp"
+#include "mp_options.hpp"
 #include "multiplayer_ui.hpp"
 #include "widgets/slider.hpp"
 #include "widgets/combo.hpp"
@@ -43,9 +45,12 @@
 
 private:
 
+	void synchronize_selections();
+
 	bool local_players_only_;
 
 	tooltips::manager tooltip_manager_;
+	int era_selection_;
 	int map_selection_;
 	int mp_countdown_init_time_;
 	int mp_countdown_reservoir_time_;
@@ -53,6 +58,7 @@
 
 	std::vector<std::string> user_maps_;
 	std::vector<std::string> map_options_;
+	config available_mods_;
 
 	/**
 	 * Due to maps not available the index of the selected map and mp scenarios
@@ -91,11 +97,13 @@
 	gui::button shroud_game_;
 	gui::button observers_game_;
 	gui::button shuffle_sides_;
+	gui::button options_;
 	gui::button cancel_game_;
 	gui::button launch_game_;
 	gui::button regenerate_map_;
 	gui::button generator_settings_;
 	gui::button password_button_;
+	gui::button choose_mods_;
 
 	gui::combo era_combo_;
 	gui::combo vision_combo_;
@@ -108,6 +116,9 @@
 
 	int num_turns_;
 	mp_game_settings parameters_;
+
+	depcheck::manager dependency_manager_;
+	options::manager options_manager_;
 };
 
 } // end namespace mp
Index: src/gui/dialogs/mp_create_game_choose_mods.hpp
===================================================================
--- src/gui/dialogs/mp_create_game_choose_mods.hpp	(revision 0)
+++ src/gui/dialogs/mp_create_game_choose_mods.hpp	(working copy)
@@ -0,0 +1,67 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#ifndef GUI_DIALOGS_MP_CREATE_GAME_CHOOSE_MODS_HPP_INCLUDED
+#define GUI_DIALOGS_MP_CREATE_GAME_CHOOSE_MODS_HPP_INCLUDED
+
+#include "gui/dialogs/dialog.hpp"
+#include "gui/widgets/listbox.hpp"
+#include "gui/widgets/button.hpp"
+#include <utility>
+#include <vector>
+#include <string>
+
+class config;
+
+namespace gui2 {
+
+class tmp_create_game_choose_mods : public tdialog
+{
+public:
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param game_cfg 		the config which contains the information for the
+	 * 						modifications
+	 * @param result [in]	the list of the currently activated modifications
+	 * @param result [out]	the list of all activated modifications
+	 */
+	tmp_create_game_choose_mods(const config& game_cfg,
+								std::vector<std::string>& result);
+
+private:
+
+	/** Inherited from tdialog, implemented by REGISTER_DIALOG. */
+	virtual const std::string& window_id() const;
+
+	/** Inherited from tdialog */
+	void pre_show(CVideo &video, twindow &window);
+
+	/** Inherited from tdialog */
+	void post_show(twindow &window);
+
+	/** a reference to the variable the result should be written into */
+	std::vector<std::string>& result_;
+
+	/** a reference to the config which contains the info about modifications*/
+	const config& game_cfg_;
+
+	/** a pointer to the listbox which displays the items */
+	gui2::tlistbox *mod_list_;
+};
+
+} // namespace gui2
+
+#endif 
Index: src/gui/dialogs/mp_depcheck_confirm_change.hpp
===================================================================
--- src/gui/dialogs/mp_depcheck_confirm_change.hpp	(revision 0)
+++ src/gui/dialogs/mp_depcheck_confirm_change.hpp	(working copy)
@@ -0,0 +1,51 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#ifndef GUI_DIALOGS_MP_DEPCHECK_CONFIRM_CHANGE_HPP_INCLUDED
+#define GUI_DIALOGS_MP_DEPCHECK_CONFIRM_CHANGE_HPP_INCLUDED
+
+#include "gui/dialogs/dialog.hpp"
+#include <vector>
+#include <string>
+
+namespace gui2
+{
+
+class tmp_depcheck_confirm_change
+		: public tdialog
+{
+public:
+	/**
+	 * Constructor.
+	 * 
+	 * @param action 		true if the listed modifications are to be enabled,
+	 * 						false if they're to be disabled
+	 * @param mods 			the names of the affected modifications
+	 * @param requester 	the name of the component which requests the change
+	 * 
+	 */
+	tmp_depcheck_confirm_change(bool action, 
+							    const std::vector<std::string>& mods,
+							    const std::string& requester );
+
+protected:
+
+	/** Inherited from tdialog, implemented by REGISTER_DIALOG. */
+	virtual const std::string& window_id() const;
+
+};
+
+} //namespace gui2
+
+#endif
Index: src/gui/dialogs/mp_depcheck_select_new.cpp
===================================================================
--- src/gui/dialogs/mp_depcheck_select_new.cpp	(revision 0)
+++ src/gui/dialogs/mp_depcheck_select_new.cpp	(working copy)
@@ -0,0 +1,110 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#define GETTEXT_DOMAIN "wesnoth-lib"
+
+#include "gui/dialogs/mp_depcheck_select_new.hpp"
+
+#include "gui/widgets/settings.hpp"
+#include "gui/widgets/window.hpp"
+#include "gui/widgets/listbox.hpp"
+#include "gettext.hpp"
+
+namespace gui2
+{
+
+/*WIKI
+ * @page = GUIWindowDefinitionWML
+ * @order = 2_mp_depcheck_select_new
+ * 
+ * == MP Dependency Check: Select New ==
+ * 
+ * Offers a list of compatible items if a currently selected one is
+ * incompatible. Currently used for switching era or map.
+ * 
+ * @begin{table}{dialog_widgets}
+ * 
+ * message & & label & m &
+ * 		displays the details of the required changes $
+ * 
+ * itemlist & & listbox & m &
+ * 		displays the available items to choose from $
+ * 
+ * cancel & & button & m &
+ * 		refuse to apply any changes $
+ * 
+ * ok & & button & m &
+ * 		select the chosen item $
+ * 
+ * @end{table}
+ * 
+ */
+
+REGISTER_DIALOG(mp_depcheck_select_new)
+
+tmp_depcheck_select_new::tmp_depcheck_select_new
+				(	mp::depcheck::component_type	name,
+					const std::vector<std::string>&	items	)
+	: items_(items)
+	, result_(-1)
+{
+
+	std::string message;
+
+	switch (name)
+	{
+		case mp::depcheck::SCENARIO:
+			message = _(	"The currently chosen scenario " \
+							"is not compatible with your setup." \
+							"\nPlease select a compatible one.");
+			break;
+		case mp::depcheck::ERA:
+			message = _(	"The currently chosen era " \
+							"is not compatible with your setup." \
+							"\nPlease select a compatible one.");
+			break;
+		case mp::depcheck::MODIFICATION:
+		//currently this can't happen, but be prepared for anything...
+			message = _(	"The currently chosen modification " \
+							"is not compatible with your setup." \
+							"\nPlease select a compatible one.");
+	}
+
+	register_label("message", false, message);
+
+}
+
+void tmp_depcheck_select_new::pre_show(CVideo& /*video*/, twindow& window)
+{
+	tlistbox& listbox = find_widget<tlistbox>(&window, "itemlist", false);
+
+	BOOST_FOREACH(const std::string& item, items_) {
+		string_map current;
+		current.insert(std::make_pair("label", item));
+
+		listbox.add_row(current);
+	}
+
+	listbox.select_row(0);
+}
+
+void tmp_depcheck_select_new::post_show(twindow& window)
+{
+	if (get_retval() == twindow::OK) {
+		tlistbox& listbox = find_widget<tlistbox>(&window, "itemlist", false);
+		result_ = listbox.get_selected_row();
+	}
+}
+
+}
Index: src/gui/dialogs/mp_create_game_choose_mods.cpp
===================================================================
--- src/gui/dialogs/mp_create_game_choose_mods.cpp	(revision 0)
+++ src/gui/dialogs/mp_create_game_choose_mods.cpp	(working copy)
@@ -0,0 +1,114 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#define GETTEXT_DOMAIN "wesnoth-lib"
+
+#include "gui/dialogs/mp_create_game_choose_mods.hpp"
+
+#include "game_preferences.hpp"
+#include "gui/dialogs/field.hpp"
+#include "gui/dialogs/helper.hpp"
+#include "gui/widgets/settings.hpp"
+#include "gui/widgets/toggle_button.hpp"
+#include "../../settings.hpp"
+#include "gettext.hpp"
+
+namespace gui2 {
+
+/*WIKI
+ * @page = GUIWindowDefinitionWML
+ * @order = 2_mp_create_game_choose_mods
+ *
+ * == Create Game: Choose Modifications ==
+ *
+ * The dialog for selecting modifications.
+ * 
+ * @begin{table}{dialog_widgets}
+ * 
+ * mod_list & & listbox & m &
+ * 		displays the list of the available modifications $
+ *
+ * -checkbox & & toggle_button & o &
+ * 		enable/disable a modification $
+ *
+ * -name & & label & o &
+ * 		displays the modification's name $
+ *
+ * -description & & label & o &
+ * 		displays the modification's description $
+ * 
+ * ok & & button & m &
+ * 		closes the dialog, applies changes $
+ *
+ * cancel & & button & m &
+ * 		closes the dialog, discards changes $
+ * 
+ * @end{table}
+ */
+
+REGISTER_DIALOG(mp_create_game_choose_mods)
+
+tmp_create_game_choose_mods::tmp_create_game_choose_mods
+					(const config& game_cfg,
+					 std::vector<std::string>& result)
+	: result_(result)
+	, game_cfg_(game_cfg)
+{
+}
+
+void tmp_create_game_choose_mods::pre_show(CVideo &/*video*/, twindow &window)
+{
+	mod_list_ = find_widget<tlistbox>(&window, "mod_list", false, true);
+	std::vector<string_map>::iterator mod_itor;
+
+	BOOST_FOREACH (const config& mod, game_cfg_.child_range("modification")) {
+
+		string_map column;
+		std::map<std::string, string_map> item;
+		column["label"] = mod["name"];
+		item.insert(std::make_pair("name", column));
+		column["label"] = mod["description"];
+		item.insert(std::make_pair("description", column));
+
+		mod_list_->add_row(item);
+
+		tgrid *grid = mod_list_->get_row_grid(mod_list_->get_item_count()-1);
+		ttoggle_button &checkbox =
+					find_widget<ttoggle_button>(grid, "checkbox", false);
+
+		checkbox.set_value(std::find(	result_.begin(), result_.end(),
+										mod["id"]) != result_.end());
+	}
+
+}
+
+void tmp_create_game_choose_mods::post_show(twindow& /*window*/)
+{
+	if (get_retval() == twindow::OK) {
+		result_.clear();
+
+		for(unsigned int i = 0; i < mod_list_->get_item_count(); i++) {
+			const tgrid *grid = mod_list_->get_row_grid(i);
+			const ttoggle_button &checkbox =
+						find_widget<const ttoggle_button>(grid, "checkbox", false);
+
+			if (checkbox.get_value()) {
+				result_.push_back(game_cfg_.child("modification", i)["id"]);
+			}
+		}
+	}
+}
+
+} // namespace gui2
+
Index: src/gui/dialogs/mp_depcheck_select_new.hpp
===================================================================
--- src/gui/dialogs/mp_depcheck_select_new.hpp	(revision 0)
+++ src/gui/dialogs/mp_depcheck_select_new.hpp	(working copy)
@@ -0,0 +1,66 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#ifndef GUI_DIALOGS_MP_DEPCHECK_SELECT_NEW_HPP_INCLUDED
+#define GUI_DIALOGS_MP_DEPCHECK_SELECT_NEW_HPP_INCLUDED
+
+#include "gui/dialogs/dialog.hpp"
+#include "mp_depcheck.hpp"
+#include <vector>
+
+
+namespace gui2
+{
+
+class tmp_depcheck_select_new
+		: public tdialog
+{
+public:
+	/**
+	 * Constructor.
+	 * 
+	 * @param name 		the type of which we want to select a new item
+	 * @param options 	the names of the components which can be choosed
+	 */
+	tmp_depcheck_select_new(mp::depcheck::component_type name,
+							const std::vector<std::string>&	options);
+
+	/**
+	 * Returns the selected item.
+	 * 
+	 * @return 		the index of the selected item, or -1 if none was selected
+	 * 				(the dialog was closed with the cancel button)
+	 */
+	int result() const { return result_; }
+
+protected:
+	/** Inherited from tdialog, implemented by REGISTER_DIALOG. */
+	virtual const std::string& window_id() const;
+
+	/** Inherited from tdialog */
+	virtual void pre_show(CVideo& video, twindow& window);
+
+	/** Inherited from tdialog */
+	virtual void post_show(twindow& window);
+
+private:
+	/** the options available */
+	std::vector<std::string> items_;
+
+	/** the index of the selected item */
+	int result_;
+};
+
+}
+#endif
Index: src/gui/dialogs/mp_depcheck_confirm_change.cpp
===================================================================
--- src/gui/dialogs/mp_depcheck_confirm_change.cpp	(revision 0)
+++ src/gui/dialogs/mp_depcheck_confirm_change.cpp	(working copy)
@@ -0,0 +1,77 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#define GETTEXT_DOMAIN "wesnoth-lib"
+
+#include "gui/dialogs/mp_depcheck_confirm_change.hpp"
+
+#include "gui/widgets/settings.hpp"
+#include "gui/widgets/window.hpp"
+#include "formula_string_utils.hpp"
+#include "gettext.hpp"
+
+namespace gui2
+{
+
+/*WIKI
+ * @page = GUIWindowDefinitionWML
+ * @order = 2_mp_depcheck_confirm_change
+ * 
+ * == MP Dependency Check: Confirm Change ==
+ * 
+ * Asks the user to confirm a change required to proceed. Currently used
+ * for enabling/disabling modifications
+ * 
+ * @begin{table}{dialog_widgets}
+ * 
+ * message & & label & m &
+ * 		displays the details of the required changes $
+ * 
+ * itemlist & & scroll_label & m &
+ * 		displays the list of affected items $
+ * 
+ * cancel & & button & m &
+ * 		refuse to apply changes $
+ * 
+ * ok & & button & m &
+ * 		agree to apply changes $
+ * 
+ * @end{table}
+ */
+
+REGISTER_DIALOG(mp_depcheck_confirm_change)
+
+tmp_depcheck_confirm_change::tmp_depcheck_confirm_change
+			(bool action,
+			 const std::vector<std::string>& mods,
+			 const std::string&	requester)
+{
+	utils::string_map symbols;
+	symbols["requester"] = requester;
+	std::string message;
+	if (action) {
+		message = vgettext("$requester requires the following modifications to be enabled:", symbols);
+	} else {
+		message = vgettext("$requester requires the following modifications to be disabled:", symbols);
+	}
+
+	std::string list = "\t";
+	list += utils::join(mods, "\n\t");
+
+	register_label("message", false, message);
+
+	register_label("itemlist", false, list);
+}
+
+}
Index: src/multiplayer_lobby.cpp
===================================================================
--- src/multiplayer_lobby.cpp	(revision 54884)
+++ src/multiplayer_lobby.cpp	(working copy)
@@ -159,6 +159,9 @@
 		font_color = font::DISABLED_COLOR;
 		no_era_string = _(" (Unknown Era)");
 	}
+	if(!game.have_all_mods && font_color != font::BAD_COLOR) {
+		font_color = font::DISABLED_COLOR;
+	}
 
 	const surface status_text(font::get_rendered_text(game.status,
 	    font::SIZE_NORMAL, font_color));
@@ -179,7 +182,7 @@
 	}
 
 	// Second line
-	ypos = item_rect.y + item_rect.h/2;
+	ypos = item_rect.y + item_rect.h/3 + margin_;
 
 	// Draw map info
 	const surface map_info_surf(font::get_rendered_text(
@@ -191,6 +194,18 @@
 	}
 
 	// Third line
+	ypos = item_rect.y + 2*item_rect.h/3 - margin_;
+
+	// Draw modifications info
+	const surface mod_info_surf(font::get_rendered_text(
+	    font::make_text_ellipsis(game.mod_info, font::SIZE_NORMAL,
+	        (item_rect.x + item_rect.w) - xpos - margin_),
+		font::SIZE_NORMAL, font::NORMAL_COLOR));
+	if(mod_info_surf) {
+		video().blit_surface(xpos, ypos - mod_info_surf->h/2, mod_info_surf);
+	}
+
+	// Fourth line
 	ypos = item_rect.y + item_rect.h  - margin_;
 
 	// Draw observer icon
@@ -525,6 +540,32 @@
 			games_.back().map_info += _("Unknown scenario");
 			verified = false;
 		}
+
+		games_.back().mod_info += "Modifications: ";
+
+		if (!game.child_or_empty("modification").empty()) {
+			games_.back().have_all_mods = true;
+			BOOST_FOREACH (const config& m, game.child_range("modification")) {
+				const config& mod_cfg = game_config.find_child("modification", "id", m["id"]);
+				if (mod_cfg) {
+					games_.back().mod_info += mod_cfg["name"].str();
+					games_.back().mod_info += ", ";
+				} else {
+					games_.back().mod_info += m["id"].str();
+					if (m["require_modification"].to_bool(false)) {
+						games_.back().have_all_mods = false;
+						games_.back().mod_info += _(" (missing)");
+					}
+					games_.back().mod_info += ", ";
+				}
+			}
+			games_.back().mod_info.erase(games_.back().mod_info.size()-2, 2);
+		} else {
+			games_.back().mod_info += "none";
+			games_.back().have_all_mods = true;
+		}
+
+
 		if (games_.back().reloaded) {
 			games_.back().map_info += " — ";
 			games_.back().map_info += _("Reloaded game");
Index: src/game_preferences.hpp
===================================================================
--- src/game_preferences.hpp	(revision 54884)
+++ src/game_preferences.hpp	(working copy)
@@ -23,6 +23,7 @@
 #include "preferences.hpp"
 
 #include <set>
+#include <vector>
 
 namespace preferences {
 
@@ -143,6 +144,9 @@
 	int turns();
 	void set_turns(int value);
 
+	const config& options();
+	void set_options(const config& values);
+
 	bool skip_mp_replay();
 	void set_skip_mp_replay(bool value);
 
@@ -172,6 +176,9 @@
 	int map();
 	void set_map(int value);
 
+	const std::vector<std::string>& modifications();
+	void set_modifications(const std::vector<std::string>& value);
+
 	bool show_ai_moves();
 	void set_show_ai_moves(bool value);
 
Index: src/play_controller.cpp
===================================================================
--- src/play_controller.cpp	(revision 54884)
+++ src/play_controller.cpp	(working copy)
@@ -279,11 +279,17 @@
 	browse_ = true;
 
 	init_managers();
-	// add era events for MP game
+	// add era & mod events for MP game
 	if (const config &era_cfg = level_.child("era")) {
 		game_events::add_events(era_cfg.child_range("event"), "era_events");
 	}
 
+	if (level_.child_or_empty("modification")) {
+		BOOST_FOREACH (const config& mod_cfg, level_.child_range("modification")) {
+			game_events::add_events(mod_cfg.child_range("event"), 
+									"mod_" + mod_cfg["id"].str() + "_events");
+		}
+	}
 	loadscreen::global_loadscreen->start_stage("start game");
 	loadscreen_manager->reset();
 }
Index: src/multiplayer_connect.cpp
===================================================================
--- src/multiplayer_connect.cpp	(revision 54884)
+++ src/multiplayer_connect.cpp	(working copy)
@@ -36,6 +36,7 @@
 #include "formula_string_utils.hpp"
 #include "tod_manager.hpp"
 #include "wml_exception.hpp"
+#include "mp_options.hpp"
 
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
@@ -1639,6 +1640,10 @@
 		level_["turns"] = num_turns_;
 		level_.add_child("multiplayer", params_.to_config());
 
+		// Convert options to events
+		level_.add_child_at("event", mp::options::to_event(params_.options
+				.find_child("multiplayer", "id", params_.mp_scenario)), 0);
+
 		params_.hash = level_.hash();
 		level_["next_underlying_unit_id"] = 0;
 		n_unit::id_manager::instance().clear();
@@ -1687,9 +1692,24 @@
 		BOOST_FOREACH(const config &e, era_cfg.child_range("multiplayer_side")) {
 			era_sides_.push_back(&e);
 		}
-		level_.add_child("era", era_cfg);
+		config& cfg = level_.add_child("era", era_cfg);
+
+		// Convert options to event
+		cfg.add_child_at("event", mp::options::to_event
+				(params_.options.find_child("era", "id", era)), 0);
 	}
 
+	// Add modifications
+	const std::vector<std::string>& mods = params_.active_mods;
+	for (unsigned i = 0; i<mods.size(); i++) {
+		config& cfg = level_.add_child("modification",
+					game_config().find_child("modification", "id", mods[i]));
+
+		// Convert options to event
+		cfg.add_child_at("event", mp::options::to_event
+				(params_.options.find_child("modification", "id", mods[i])), 0);
+	}
+
 	gold_title_label_.hide(params_.saved_game);
 	income_title_label_.hide(params_.saved_game);
 
Index: src/mp_depcheck.cpp
===================================================================
--- src/mp_depcheck.cpp	(revision 0)
+++ src/mp_depcheck.cpp	(working copy)
@@ -0,0 +1,710 @@
+/*
+   Copyright (C) 2012 by Boldizsár Lipka <lipka.boldizsar@gmail.com>
+   Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY.
+
+   See the COPYING file for more details.
+*/
+
+#include "mp_depcheck.hpp"
+
+#include <algorithm>
+#include <map>
+
+#include "formula_string_utils.hpp"
+#include "gettext.hpp"
+
+#include "gui/dialogs/mp_depcheck_confirm_change.hpp"
+#include "gui/dialogs/mp_depcheck_select_new.hpp"
+#include "gui/dialogs/message.hpp"
+
+namespace {
+//helper function
+void copy_keys(config& out,
+			   const config& in,
+			   const std::string& type,
+			   bool copy_force_key=false)
+{
+	if (in.has_attribute("allow_" + type)) {
+		out["allow_" + type] = in["allow_" + type];
+	} else if (in.has_attribute("disallow_" + type)) {
+		out["disallow_" + type] = in["disallow_" + type];
+	}
+
+	if (in.has_attribute("ignore_incompatible_" + type)) {
+		out["ignore_incompatible_" + type] = in["ignore_incompatible_" + type];
+	}
+
+	if (copy_force_key) {
+		if (in.has_attribute("force_" + type)) {
+			out["force_" + type] = in["force_" + type];
+		}
+	}
+}
+
+//helper function
+inline bool contains(const std::vector<std::string>& container,
+					 const std::string& value)
+{
+	return 	std::find(container.begin(), container.end(), value)
+			!= container.end();
+}
+
+} //anonymous namespace
+
+namespace mp
+{
+
+namespace depcheck
+{
+
+manager::manager(const config& gamecfg, CVideo& video)
+	: video_(video)
+	, depinfo_()
+	, era_()
+	, scenario_()
+	, mods_()
+	, prev_era_()
+	, prev_scenario_()
+	, prev_mods_()
+{
+	BOOST_FOREACH (const config& cfg, gamecfg.child_range("modification")) {
+		config info;
+		info["id"] = cfg["id"];
+		info["name"] = cfg["name"];
+
+		copy_keys(info, cfg, "scenario");
+		copy_keys(info, cfg, "era");
+		copy_keys(info, cfg, "modification");
+
+		depinfo_.add_child("modification", info);
+	}
+
+	BOOST_FOREACH (const config& cfg, gamecfg.child_range("era")) {
+		config info;
+		info["id"] = cfg["id"];
+		info["name"] = cfg["name"];
+
+		copy_keys(info, cfg, "scenario");
+		copy_keys(info, cfg, "modification", true);
+
+		depinfo_.add_child("era", info);
+	}
+
+	BOOST_FOREACH (const config& cfg, gamecfg.child_range("multiplayer")) {
+		config info;
+		info["id"] = cfg["id"];
+		info["name"] = cfg["name"];
+
+		copy_keys(info, cfg, "era");
+		copy_keys(info, cfg, "modification", true);
+
+		depinfo_.add_child("scenario", info);
+	}
+}
+
+
+void manager::save_state() {
+	prev_era_ = era_;
+	prev_scenario_ = scenario_;
+	prev_mods_ = mods_;
+}
+
+void manager::revert() {
+	era_ = prev_era_;
+	scenario_ = prev_scenario_;
+	mods_ = prev_mods_;
+}
+
+bool manager::exists(const elem& e) const
+{
+	BOOST_FOREACH (const config& cfg, depinfo_.child_range(e.type)) {
+		if (cfg["id"] == e.id) {
+			return true;
+		}
+	}
+
+	return false;
+}
+
+std::vector<std::string>
+		manager::get_required_not_installed(const elem& e) const
+{
+	std::vector<std::string> result;
+
+	std::vector<std::string> items = get_required(e);
+
+	BOOST_FOREACH (const std::string& str, items) {
+		if (!exists(elem(str, "modification"))) {
+			result.push_back(str);
+		}
+	}
+
+	return result;
+}
+
+std::vector<std::string> manager::get_required(const elem& e) const
+{
+	std::vector<std::string> result;
+
+	if (e.type == "modification") {
+		return result;
+	}
+
+	config data = depinfo_.find_child(e.type, "id", e.id);
+
+	if (data.has_attribute("force_modification")) {
+		result = utils::split(data["force_modification"], ',');
+	}
+
+	return result;
+}
+
+std::vector<std::string> manager::get_required_not_enabled(const elem& e) const
+{
+	std::vector<std::string> required = get_required(e);
+	std::vector<std::string> result;
+
+	BOOST_FOREACH (std::string str, required) {
+		if (!contains(mods_, str)) {
+			result.push_back(str);
+		}
+	}
+
+	return result;
+}
+
+std::vector<std::string> manager::get_conflicting_enabled(const elem& e) const
+{
+	std::vector<std::string> result;
+
+	BOOST_FOREACH(const std::string& mod, mods_) {
+		if (conflicts(elem(mod, "modification"), e)) {
+			result.push_back(mod);
+		}
+	}
+
+	return result;
+}
+
+bool manager::conflicts(const elem& elem1, const elem& elem2, bool directonly) const
+{
+	if (elem1 == elem2) {
+		return false;
+	}
+
+	// We ignore inexistent elements at this point, they will generate
+	// errors in change_era()/change_scenario() anyways.
+	if (!exists(elem1) || !exists(elem2)) {
+		return false;
+	}
+
+	config data1 = depinfo_.find_child(elem1.type, "id", elem1.id);
+	config data2 = depinfo_.find_child(elem2.type, "id", elem2.id);
+
+	// Whether we should skip the check entirely
+	if (data1.has_attribute("ignore_incompatible_" + elem2.type)) {
+		std::vector<std::string> ignored =
+						utils::split(data1["ignore_incompatible_" + elem2.type]);
+
+		if (contains(ignored, elem2.id)) {
+			return false;
+		}
+	}
+
+	if (data2.has_attribute("ignore_incompatible_" + elem1.type)) {
+		std::vector<std::string> ignored =
+						utils::split(data2["ignore_incompatible_" + elem1.type]);
+
+		if (contains(ignored, elem1.id)) {
+			return false;
+		}
+	}
+
+	bool result = false;
+
+	// Checking for direct conflicts between elem1 and elem2
+	if (data1.has_attribute("allow_" + elem2.type)) {
+		std::vector<std::string> allowed =
+						utils::split(data1["allow_" + elem2.type]);
+
+		result = !contains(allowed, elem2.id) && !requires(elem1, elem2);
+	} else if (data1.has_attribute("disallow_" + elem2.type)) {
+		std::vector<std::string> disallowed =
+						utils::split(data1["disallow_" + elem2.type]);
+
+		result = contains(disallowed, elem2.id);
+	}
+
+	if (data2.has_attribute("allow_" + elem1.type)) {
+		std::vector<std::string> allowed =
+						utils::split(data2["allow_" + elem1.type]);
+
+		result = result || (!contains(allowed, elem1.id) && !requires(elem2, elem1));
+	} else if (data2.has_attribute("disallow_" + elem1.type)) {
+		std::vector<std::string> disallowed =
+						utils::split(data2["disallow_" + elem1.type]);
+
+		result = result || contains(disallowed, elem1.id);
+	}
+
+	if (result) {
+		return true;
+	}
+
+	// Checking for indirect conflicts (i.e. conflicts between dependencies)
+	if (!directonly) {
+		std::vector<std::string>	req1 = get_required(elem1),
+									req2 = get_required(elem2);
+
+		BOOST_FOREACH (const std::string& s, req1) {
+			elem m(s, "modification");
+
+			if (conflicts(elem2, m, true)) {
+				return true;
+			}
+		}
+
+		BOOST_FOREACH (const std::string& s, req2) {
+			elem m(s, "modification");
+
+			if (conflicts(elem1, m, true)) {
+				return true;
+			}
+		}
+
+		BOOST_FOREACH (const std::string& id1, req1) {
+			elem m1(id1, "modification");
+
+			BOOST_FOREACH (const std::string& id2, req2) {
+				elem m2(id2, "modification");
+
+				if (conflicts(m1, m2)) {
+					return true;
+				}
+			}
+		}
+	}
+
+	return false;
+}
+
+
+bool manager::requires(const elem& elem1, const elem& elem2) const
+{
+	if (elem2.type != "modification") {
+		return false;
+	}
+
+	config data = depinfo_.find_child(elem1.type, "id", elem1.id);
+
+	if (data.has_attribute("force_modification")) {
+		std::vector<std::string> required =
+							utils::split(data["force_modification"]);
+
+		return contains(required, elem2.id);
+	}
+
+	return false;
+}
+
+void manager::try_era(const std::string& id, bool force)
+{
+	save_state();
+
+	if (force) {
+		era_ = id;
+	} else if (!change_era(id)) {
+		revert();
+	}
+}
+
+void manager::try_scenario(const std::string& id, bool force)
+{
+	save_state();
+
+	if (force) {
+		scenario_ = id;
+	} else if (!change_scenario(id)) {
+		revert();
+	}
+}
+
+void manager::try_modifications(const std::vector<std::string>& ids, bool force)
+{
+	save_state();
+	
+	if (force) {
+		mods_ = ids;
+	} else if (!change_modifications(ids)) {
+		revert();
+	}
+}
+
+void manager::try_era_by_index(int index, bool force)
+{
+	try_era(depinfo_.child("era", index)["id"], force);
+}
+
+void manager::try_scenario_by_index(int index, bool force)
+{
+	try_scenario(depinfo_.child("scenario", index - 1)["id"], force);
+}
+
+int manager::get_era_index() const
+{
+	int result = 0;
+
+	BOOST_FOREACH (const config& i, depinfo_.child_range("era"))
+	{
+		if (i["id"] == era_) {
+			return result;
+		}
+		result++;
+	}
+
+	return -1;
+}
+
+int manager::get_scenario_index() const
+{
+	int result = 1;
+
+	BOOST_FOREACH (const config& i, depinfo_.child_range("scenario"))
+	{
+		if (i["id"] == scenario_) {
+			return result;
+		}
+		result++;
+	}
+
+	return -1;
+}
+
+
+bool manager::enable_mods_dialog(const std::vector<std::string>& mods)
+{
+	std::vector<std::string> items;
+	BOOST_FOREACH (const std::string& mod, mods) {
+		items.push_back(depinfo_.find_child("modification", "id", mod)["name"]);
+	}
+
+	gui2::tmp_depcheck_confirm_change dialog(true, items, _("A component"));
+	return dialog.show(video_);
+}
+
+bool manager::disable_mods_dialog(const std::vector<std::string>& mods)
+{
+	std::vector<std::string> items;
+	BOOST_FOREACH (const std::string& mod, mods) {
+		items.push_back(depinfo_.find_child("modification", "id", mod)["name"]);
+	}
+
+	gui2::tmp_depcheck_confirm_change dialog(false, items, _("A component"));
+	return dialog.show(video_);
+}
+
+std::string manager::change_era_dialog(const std::vector<std::string>& eras)
+{
+	std::vector<std::string> items;
+	BOOST_FOREACH(const std::string& era, eras) {
+		items.push_back(depinfo_.find_child("era", "id", era)["name"]);
+	}
+
+	gui2::tmp_depcheck_select_new dialog(ERA, items);
+
+	if (dialog.show(video_)) {
+		return eras[dialog.result()];
+	}
+
+	return "";
+}
+
+std::string
+	manager::change_scenario_dialog(const std::vector<std::string>& scenarios)
+{
+	std::vector<std::string> items;
+	BOOST_FOREACH (const std::string& scenario, scenarios) {
+		items.push_back(depinfo_.find_child("scenario", "id", scenario)["name"]);
+	}
+
+	gui2::tmp_depcheck_select_new dialog(SCENARIO, items);
+	if (dialog.show(video_)) {
+		return scenarios[dialog.result()];
+	}
+
+	return "";
+}
+
+void manager::failure_dialog(const std::string& msg)
+{
+	gui2::show_message
+				(video_, _("Failed to resolve dependencies"), msg, _("OK"));
+}
+
+
+void manager::insert_element(component_type type, const config& data, int index)
+{
+	std::string type_str;
+	switch (type) {
+		case ERA:
+			type_str = "era";
+			break;
+		case SCENARIO:
+			type_str = "scenario";
+			break;
+		case MODIFICATION:
+			type_str = "modification";
+	}
+
+	depinfo_.add_child_at(type_str, data, index);
+}
+
+bool manager::change_scenario(const std::string& id)
+{
+	// Checking for missing dependencies
+	if (!get_required_not_installed(elem(id, "scenario")).empty()) {
+		std::string msg =
+			_("Scenario can't be activated. Some dependencies are missing: ");
+
+		msg +=
+			utils::join(get_required_not_installed(elem(id, "scenario")), ", ");
+
+		failure_dialog(msg);
+		return false;
+	}
+
+	scenario_ = id;
+
+	elem scen = elem(id, "scenario");
+
+	// Firstly, we check if we have to enable/disable any mods
+	std::vector<std::string> req = get_required_not_enabled(scen);
+	std::vector<std::string> con = get_conflicting_enabled(scen);
+
+	if (!req.empty()) {
+		if (!enable_mods_dialog(req)) {
+			return false;
+		}
+	}
+
+	if (!con.empty()) {
+		if (!disable_mods_dialog(con)) {
+			return false;
+		}
+	}
+
+	std::vector<std::string> newmods = req;
+	BOOST_FOREACH (const std::string& i, mods_) {
+		if (!contains(con, i)) {
+			newmods.push_back(i);
+		}
+	}
+
+
+	mods_ = newmods;
+
+	// Now checking if the currently selected era conflicts the scenario
+	// and changing era if necessary
+	if (!conflicts(scen, elem(era_, "era"))) {
+		return true;
+	}
+
+	std::vector<std::string> compatible;
+	BOOST_FOREACH (const config& i, depinfo_.child_range("era")) {
+		if (!conflicts(scen, elem(i["id"], "era"))) {
+			compatible.push_back(i["id"]);
+		}
+	}
+
+	if (!compatible.empty()) {
+		era_ = change_era_dialog(compatible);
+	} else {
+		failure_dialog(_("No compatible eras found."));
+		return false;
+	}
+
+	if (era_.empty()) {
+		return false;
+	}
+
+	return change_era(era_);
+}
+
+bool manager::change_era(const std::string& id)
+{
+	// Checking for missing dependenciess
+	if (!get_required_not_installed(elem(id, "era")).empty()) {
+		std::string msg =
+				_("Era can't be activated. Some dependencies are missing: ");
+
+		msg += utils::join(get_required_not_installed(elem(id, "era")), ", ");
+		failure_dialog(msg);
+		return false;
+	}
+
+	era_ = id;
+
+	elem era = elem(id, "era");
+
+	std::vector<std::string> req = get_required_not_enabled(era);
+	std::vector<std::string> con = get_conflicting_enabled(era);
+
+	// Firstly, we check if we have to enable/disable any mods
+	if (!req.empty()) {
+		if (!enable_mods_dialog(req)) {
+			return false;
+		}
+	}
+
+	if (!con.empty()) {
+		if (!disable_mods_dialog(con)) {
+			return false;
+		}
+	}
+
+	std::vector<std::string> newmods = req;
+	BOOST_FOREACH (const std::string& i, mods_) {
+		if (!contains(con, i)) {
+			newmods.push_back(i);
+		}
+	}
+
+	mods_ = newmods;
+
+	// Now checking if the currently selected scenarop conflicts the era
+	// and changing scenario if necessary
+	if (!conflicts(era, elem(scenario_, "scenario"))) {
+		return true;
+	}
+
+	std::vector<std::string> compatible;
+	BOOST_FOREACH (const config& i, depinfo_.child_range("scenario")) {
+		if (!conflicts(era, elem(i["id"], "scenario"))) {
+			compatible.push_back(i["id"]);
+		}
+	}
+
+	if (!compatible.empty()) {
+		scenario_ = change_scenario_dialog(compatible);
+	} else {
+		failure_dialog(_("No compatible scenarios found."));
+		return false;
+	}
+
+	if (scenario_.empty()) {
+		return false;
+	}
+
+	return change_scenario(scenario_);
+}
+
+bool manager::change_modifications
+					(const std::vector<std::string>& modifications)
+{
+	// Checking if the selected combination of mods is valid at all
+	std::vector<std::string> filtered;
+	BOOST_FOREACH (const std::string& i, modifications) {
+		bool ok = true;
+		elem ei(i, "modification");
+		BOOST_FOREACH (const std::string& j, filtered) {
+			ok = ok && !conflicts(ei, elem(j, "modification"));
+		}
+
+		if (ok) {
+			filtered.push_back(i);
+		}
+	}
+
+	if (filtered.size() != modifications.size()) {
+		failure_dialog(_("Not all of the chosen modifications are compatible." \
+						 " Some of them will be disabled."));
+	}
+
+	mods_ = filtered;
+
+	// Checking if the currently selected era is compatible with the set
+	// modifications, and changing era if necessary
+	std::vector<std::string> compatible;
+	BOOST_FOREACH (const config& c, depinfo_.child_range("era")) {
+		elem era(c["id"], "era");
+		bool ok = true;
+		BOOST_FOREACH (const std::string& s, mods_) {
+			ok = ok && !conflicts(era, elem(s, "modification"));
+		}
+
+		if (ok) {
+			compatible.push_back(era.id);
+		}
+	}
+
+	if (!contains(compatible, era_)) {
+		if (!compatible.empty()) {
+			era_ = change_era_dialog(compatible);
+		} else {
+			failure_dialog(_("No compatible eras found."));
+			return false;
+		}
+
+		if (era_.empty()) {
+			return false;
+		}
+
+		if (!change_era(era_)) {
+			return false;
+		}
+	} else {
+		if (!change_era(era_)) {
+			return false;
+		}
+	}
+
+	compatible.clear();
+
+	// Checking if the currently selected scenario is compatible with
+	// the set modifications, and changing scenario if necessary
+	BOOST_FOREACH (const config& c, depinfo_.child_range("scenario")) {
+		elem scen(c["id"], "scenario");
+		bool ok = true;
+		BOOST_FOREACH (const std::string& s, mods_) {
+			ok = ok && !conflicts(scen, elem(s, "modification"));
+		}
+
+		if (ok) {
+			compatible.push_back(scen.id);
+		}
+	}
+
+	if (!contains(compatible, scenario_)) {
+		if (!compatible.empty()) {
+			scenario_ = change_scenario_dialog(compatible);
+		} else {
+			failure_dialog(_("No compatible scenarios found."));
+			return false;
+		}
+
+		if (scenario_.empty()) {
+			return false;
+		}
+
+		return change_scenario(scenario_);
+	} else {
+		if (!change_scenario(scenario_)) {
+			return false;
+		}
+	}
+
+	return true;
+}
+
+
+
+} //namespace depcheck
+
+} //namespace mp
Index: src/multiplayer_lobby.hpp
===================================================================
--- src/multiplayer_lobby.hpp	(revision 54884)
+++ src/multiplayer_lobby.hpp	(working copy)
@@ -44,6 +44,7 @@
 			name(),
 			map_info(),
 			map_info_size(),
+			mod_info(),
 			gold(),
 			xp(),
 			vision(),
@@ -60,7 +61,8 @@
 			use_map_settings(false),
 			verified(false),
 			password_required(false),
-			have_era(false)
+			have_era(false),
+			have_all_mods(false)
 		{
 		}
 
@@ -70,6 +72,7 @@
 		std::string name;
 		std::string map_info;
 		std::string map_info_size;
+		std::string mod_info;
 		std::string gold;
 		std::string xp;
 		std::string vision;
@@ -87,6 +90,7 @@
 		bool verified;
 		bool password_required;
 		bool have_era;
+		bool have_all_mods;
 	};
 	gamebrowser(CVideo& video, const config &map_hashes);
 	void scroll(unsigned int pos);
@@ -100,9 +104,9 @@
 	SDL_Rect get_item_rect(size_t index) const;
 	bool empty() const { return games_.empty(); }
 	bool selection_is_joinable() const
-	{ return empty() ? false : (games_[selected_].vacant_slots > 0 && !games_[selected_].started && games_[selected_].have_era); }
+	{ return empty() ? false : (games_[selected_].vacant_slots > 0 && !games_[selected_].started && games_[selected_].have_era && games_[selected_].have_all_mods); }
 	// Moderators may observe any game.
-	bool selection_is_observable() const { return empty() ? false : (games_[selected_].observers && games_[selected_].have_era) || preferences::is_authenticated(); }
+	bool selection_is_observable() const { return empty() ? false : (games_[selected_].observers && games_[selected_].have_era && games_[selected_].have_all_mods) || preferences::is_authenticated(); }
 	bool selected() const { return double_clicked_ && !empty(); }
 	void reset_selection() { double_clicked_ = false; }
 	int selection() const { return selected_; }
