Index: src/play_controller.cpp
===================================================================
--- src/play_controller.cpp	(revision 54280)
+++ src/play_controller.cpp	(working copy)
@@ -270,10 +270,16 @@
 	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")) {
+		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_lobby.cpp
===================================================================
--- src/multiplayer_lobby.cpp	(revision 54280)
+++ src/multiplayer_lobby.cpp	(working copy)
@@ -178,7 +178,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(
@@ -188,8 +188,20 @@
 	if(map_info_surf) {
 		video().blit_surface(xpos, ypos - map_info_surf->h/2, map_info_surf);
 	}
+	
+	// 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);
+	}
 
-	// Third line
+	// Fourth line
 	ypos = item_rect.y + item_rect.h  - margin_;
 
 	// Draw observer icon
@@ -524,6 +536,21 @@
 			games_.back().map_info += _("Unknown scenario");
 			verified = false;
 		}
+		
+		games_.back().mod_info += "Modifications: ";
+		
+		if (!game.child_or_empty("modification").empty()) {
+			bool first_iteration = true;
+			foreach (const config& cfg, game.child_range("modification")) {
+				games_.back().mod_info += first_iteration ? "" : ", ";
+				games_.back().mod_info += cfg["name"].str();
+				first_iteration = false;
+			}
+		} else {
+			games_.back().mod_info += "none";
+		}
+		
+		
 		if (games_.back().reloaded) {
 			games_.back().map_info += " — ";
 			games_.back().map_info += _("Reloaded game");
Index: src/multiplayer_create.hpp
===================================================================
--- src/multiplayer_create.hpp	(revision 54280)
+++ src/multiplayer_create.hpp	(working copy)
@@ -18,6 +18,7 @@
 #ifndef MULTIPLAYER_CREATE_HPP_INCLUDED
 #define MULTIPLAYER_CREATE_HPP_INCLUDED
 
+#include "mp_depcheck.hpp"
 #include "mp_game_settings.hpp"
 #include "multiplayer_ui.hpp"
 #include "widgets/slider.hpp"
@@ -43,9 +44,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 +57,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
@@ -96,6 +101,7 @@
 	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 +114,8 @@
 
 	int num_turns_;
 	mp_game_settings parameters_;
+	
+	depcheck::manager dependency_manager_;
 };
 
 } // end namespace mp
Index: src/mp_game_settings.cpp
===================================================================
--- src/mp_game_settings.cpp	(revision 54280)
+++ 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),
@@ -56,6 +58,7 @@
 	hash(),
 	mp_era(),
 	mp_scenario(),
+	active_mods(),
 	village_gold(0),
 	village_support(1),
 	xp_modifier(0),
@@ -85,6 +88,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)
@@ -116,6 +120,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();
@@ -139,6 +144,7 @@
 	hash = "";
 	mp_era = "";
 	mp_scenario = "";
+	active_mods.clear();
 	village_gold = 0;
 	village_support = 1;
 	xp_modifier = 0;
@@ -160,6 +166,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;
Index: src/multiplayer_lobby.hpp
===================================================================
--- src/multiplayer_lobby.hpp	(revision 54280)
+++ src/multiplayer_lobby.hpp	(working copy)
@@ -44,6 +44,7 @@
 			name(),
 			map_info(),
 			map_info_size(),
+			mod_info(),
 			gold(),
 			xp(),
 			vision(),
@@ -70,6 +71,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;
Index: src/CMakeLists.txt
===================================================================
--- src/CMakeLists.txt	(revision 54280)
+++ src/CMakeLists.txt	(working copy)
@@ -505,7 +505,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
@@ -563,6 +566,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/game_preferences.cpp
===================================================================
--- src/game_preferences.cpp	(revision 54280)
+++ src/game_preferences.cpp	(working copy)
@@ -52,6 +52,10 @@
 bool friends_initialized = false;
 bool ignores_initialized = false;
 
+std::vector<std::string> mp_modifications;
+
+bool modifications_initialized = false;
+
 bool authenticated = false;
 
 const char WRAP_CHAR = '@';
@@ -693,6 +697,26 @@
 	preferences::set("mp_map", value);
 }
 
+void initialize_modifications()
+{
+	mp_modifications = utils::split(preferences::get("modifications"), ',');
+	modifications_initialized = true;
+}
+
+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/SConscript
===================================================================
--- src/SConscript	(revision 54280)
+++ src/SConscript	(working copy)
@@ -349,7 +349,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
@@ -407,6 +410,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_game_settings.hpp
===================================================================
--- src/mp_game_settings.hpp	(revision 54280)
+++ 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;
Index: src/multiplayer_connect.cpp
===================================================================
--- src/multiplayer_connect.cpp	(revision 54280)
+++ src/multiplayer_connect.cpp	(working copy)
@@ -1689,6 +1689,13 @@
 		}
 		level_.add_child("era", era_cfg);
 	}
+	
+	// Add modifications
+	// TODO: implement error handling
+	const std::vector<std::string>& mods = params_.active_mods;
+	for (unsigned i = 0; i<mods.size(); i++) {
+		level_.add_child("modification", game_config().find_child("modification", "id", mods[i]));
+	}
 
 	gold_title_label_.hide(params_.saved_game);
 	income_title_label_.hide(params_.saved_game);
Index: src/scripting/lua.cpp
===================================================================
--- src/scripting/lua.cpp	(revision 54280)
+++ src/scripting/lua.cpp	(working copy)
@@ -3809,7 +3809,7 @@
 
 static char const *handled_file_tags[] = {
 	"color_palette", "color_range", "era", "event", "generator",
-	"label", "lua", "map", "menu_item", "music", "side", "sound_source", "story",
+	"label", "lua", "map", "menu_item", "modification", "music", "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
Index: src/game_preferences.hpp
===================================================================
--- src/game_preferences.hpp	(revision 54280)
+++ src/game_preferences.hpp	(working copy)
@@ -23,6 +23,7 @@
 #include "preferences.hpp"
 
 #include <set>
+#include <vector>
 
 namespace preferences {
 
@@ -171,6 +172,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/multiplayer_create.cpp
===================================================================
--- src/multiplayer_create.cpp	(revision 54280)
+++ 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"
@@ -57,11 +58,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>()),
@@ -98,6 +101,7 @@
 	regenerate_map_(disp.video(), _("Regenerate")),
 	generator_settings_(disp.video(), _("Settings...")),
 	password_button_(disp.video(), _("Set Password...")),
+	choose_mods_(disp.video(), _("Choose Modifications...")),
 	era_combo_(disp, std::vector<std::string>()),
 	vision_combo_(disp, std::vector<std::string>()),
 	name_entry_(disp.video(), 32),
@@ -105,7 +109,8 @@
 	minimap_rect_(null_rect),
 	generator_(NULL),
 	num_turns_(0),
-	parameters_()
+	parameters_(),
+	dependency_manager_(cfg, disp.video())
 {
 	// Build the list of scenarios to play
 
@@ -126,6 +131,14 @@
 	{
 		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("scenario", depinfo, i);
 	}
 
 	// Standard maps
@@ -144,8 +157,10 @@
 
 	// 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_.set_scenario_by_index(preferences::map(), true);
+	}
 	maps_menu_.set_numeric_keypress_selection(false);
 
 	turns_slider_.set_min(settings::turns_min);
@@ -237,10 +252,20 @@
 	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_.set_era_by_index(era_selection_, true);
+	
+	// Available modifications
+	foreach (const config& mod, cfg.child_range("modification")) {
+		available_mods_.add_child("modification", mod);
+	}
+	
+	parameters_.active_mods = preferences::modifications();
+	dependency_manager_.set_modifications(parameters_.active_mods, true);
+	
 
-
 	utils::string_map i18n_symbols;
 	i18n_symbols["login"] = preferences::login();
 	name_entry_.set_text(vgettext("$login|’s game", i18n_symbols));
@@ -270,8 +295,9 @@
 	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);
 
 	// When using map settings, the following variables are determined by the map,
 	// so don't store them as the new preferences.
@@ -373,6 +399,14 @@
 				, disp_.video());
 
 	}
+	
+	if(choose_mods_.pressed()) {
+		gui2::tmp_create_game_choose_mods dialog(available_mods_, parameters_.active_mods);
+		dialog.show(disp_.video());
+		
+		dependency_manager_.set_modifications(parameters_.active_mods);
+		synchronize_selections();
+	}
 
 	// Turns per game
 	const int cur_turns = turns_slider_.value();
@@ -445,9 +479,22 @@
 	buf << _("Experience modifier: ") << xpmod << "%";
 
 	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_.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_.set_scenario_by_index(map_selection_);
+		synchronize_selections();
+	}
 
 	if(map_changed) {
 		generator_.assign(NULL);
@@ -757,6 +804,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;
@@ -859,5 +908,20 @@
 	                          gui::ButtonHPadding, ca.y + ca.h - left_button->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();
+}
+
 } // namespace mp
 
Index: src/server/simple_wml.hpp
===================================================================
--- src/server/simple_wml.hpp	(revision 54280)
+++ src/server/simple_wml.hpp	(working copy)
@@ -241,6 +241,10 @@
 	const node* child(const char* name) const {
 		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 54280)
+++ src/server/server.cpp	(working copy)
@@ -2330,6 +2330,8 @@
 	}
 }
 
+#include <iostream>
+
 /**
  * Process data sent from a member of a game.
  */
@@ -2401,6 +2403,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 {
@@ -2424,6 +2427,12 @@
 				desc.set_attr("require_era", "no");
 			}
 		}
+		
+		const simple_wml::node::child_list& mlist = data.children("modification");
+		foreach (const simple_wml::node* m, mlist) {
+			desc.add_child_at("modification", 0);
+			m->copy_into(*desc.child("modification"));
+		}
 
 		// Record the full scenario in g->level()
 		g->level().swap(data);
@@ -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();
