00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "game_controller.hpp"
00017
00018 #include "about.hpp"
00019 #include "addon/manager.hpp"
00020 #include "ai/configuration.hpp"
00021 #include "builder.hpp"
00022 #include "construct_dialog.hpp"
00023 #include "gettext.hpp"
00024 #include "gui/dialogs/addon_connect.hpp"
00025 #include "gui/dialogs/campaign_difficulty.hpp"
00026 #include "gui/dialogs/campaign_selection.hpp"
00027 #include "gui/dialogs/language_selection.hpp"
00028 #include "gui/dialogs/message.hpp"
00029 #include "gui/dialogs/mp_method_selection.hpp"
00030 #include "gui/dialogs/title_screen.hpp"
00031 #include "gui/dialogs/transient_message.hpp"
00032 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00033 #include "gui/widgets/debug.hpp"
00034 #endif
00035 #include "gui/auxiliary/event/handler.hpp"
00036 #include "gui/widgets/settings.hpp"
00037 #include "gui/widgets/window.hpp"
00038 #include "intro.hpp"
00039 #include "language.hpp"
00040 #include "loadscreen.hpp"
00041 #include "log.hpp"
00042 #include "map_exception.hpp"
00043 #include "multiplayer.hpp"
00044 #include "network.hpp"
00045 #include "playcampaign.hpp"
00046 #include "preferences_display.hpp"
00047 #include "replay.hpp"
00048 #include "savegame.hpp"
00049 #include "scripting/lua.hpp"
00050 #include "statistics.hpp"
00051 #include "wml_exception.hpp"
00052 #include "gui/dialogs/mp_host_game_prompt.hpp"
00053
00054 static lg::log_domain log_config("config");
00055 #define ERR_CONFIG LOG_STREAM(err, log_config)
00056 #define WRN_CONFIG LOG_STREAM(warn, log_config)
00057 #define LOG_CONFIG LOG_STREAM(info, log_config)
00058
00059 #define LOG_GENERAL LOG_STREAM(info, lg::general)
00060 #define WRN_GENERAL LOG_STREAM(warn, lg::general)
00061 #define DBG_GENERAL LOG_STREAM(debug, lg::general)
00062
00063 static lg::log_domain log_network("network");
00064 #define ERR_NET LOG_STREAM(err, log_network)
00065
00066 static bool less_campaigns_rank(const config &a, const config &b) {
00067 return a["rank"].to_int(1000) < b["rank"].to_int(1000);
00068 }
00069
00070 game_controller::game_controller(const commandline_options& cmdline_opts, const char *appname) :
00071 game_controller_abstract(cmdline_opts),
00072 thread_manager(),
00073 font_manager_(),
00074 prefs_manager_(),
00075 image_manager_(),
00076 main_event_context_(),
00077 hotkey_manager_(),
00078 music_thinker_(),
00079 resize_monitor_(),
00080 paths_manager_(),
00081 test_scenario_("test"),
00082 screenshot_map_(),
00083 screenshot_filename_(),
00084 game_config_(),
00085 old_defines_map_(),
00086 state_(),
00087 multiplayer_server_(),
00088 jump_to_multiplayer_(false),
00089 jump_to_campaign_(false, -1, "", ""),
00090 jump_to_editor_(false),
00091 cache_(game_config::config_cache::instance())
00092 {
00093 bool no_music = false;
00094 bool no_sound = false;
00095
00096
00097 if(!game_config::path.empty() &&
00098 #ifdef _WIN32
00099
00100 game_config::path.c_str()[1] != ':'
00101 #else
00102 game_config::path[0] != '/'
00103 #endif
00104 )
00105 {
00106 game_config::path = get_cwd() + '/' + game_config::path;
00107 font_manager_.update_font_path();
00108 }
00109
00110 const std::string app_basename = file_name(appname);
00111 jump_to_editor_ = app_basename.find("editor") != std::string::npos;
00112
00113 if (cmdline_opts_.campaign) {
00114 jump_to_campaign_.jump_ = true;
00115 jump_to_campaign_.campaign_id_ = *cmdline_opts_.campaign;
00116 std::cerr << "selected campaign id: [" << jump_to_campaign_.campaign_id_ << "]\n";
00117
00118 if (cmdline_opts_.campaign_difficulty) {
00119 jump_to_campaign_.difficulty_ = *cmdline_opts_.campaign_difficulty;
00120 std::cerr << "selected difficulty: [" << jump_to_campaign_.difficulty_ << "]\n";
00121 }
00122 else
00123 jump_to_campaign_.difficulty_ = -1;
00124
00125 if (cmdline_opts_.campaign_scenario) {
00126 jump_to_campaign_.scenario_id_ = *cmdline_opts_.campaign_scenario;
00127 std::cerr << "selected scenario id: [" << jump_to_campaign_.scenario_id_ << "]\n";
00128 }
00129 }
00130 if (cmdline_opts_.clock)
00131 gui2::show_debug_clock_button = true;
00132 if (cmdline_opts_.debug) {
00133 game_config::debug = true;
00134 game_config::mp_debug = true;
00135 }
00136 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00137 if (cmdline_opts_.debug_dot_domain)
00138 gui2::tdebug_layout_graph::set_domain (*cmdline_opts_.debug_dot_domain);
00139 if (cmdline_opts_.debug_dot_level)
00140 gui2::tdebug_layout_graph::set_level (*cmdline_opts_.debug_dot_level);
00141 #endif
00142 if (cmdline_opts_.editor)
00143 {
00144 jump_to_editor_ = true;
00145 if(!cmdline_opts_.editor->empty())
00146 game::load_game_exception::game = *cmdline_opts_.editor;
00147 }
00148 if (cmdline_opts_.fps)
00149 preferences::set_show_fps(true);
00150 if (cmdline_opts_.fullscreen)
00151 preferences::set_fullscreen(true);
00152 if (cmdline_opts_.load)
00153 game::load_game_exception::game = *cmdline_opts_.load;
00154 if (cmdline_opts_.max_fps) {
00155 int fps;
00156
00157 fps = lexical_cast_default<int>("", 50);
00158 fps = *cmdline_opts_.max_fps;
00159 fps = std::min<int>(fps, 1000);
00160 fps = std::max<int>(fps, 1);
00161 fps = 1000 / fps;
00162
00163 if(1000 % fps != 0) {
00164 ++fps;
00165 }
00166 preferences::set_draw_delay(fps);
00167 }
00168 if (cmdline_opts_.nogui) {
00169 no_sound = true;
00170 preferences::disable_preferences_save();
00171 }
00172 if (cmdline_opts_.new_storyscreens)
00173
00174
00175
00176 set_new_storyscreen(true);
00177 if (cmdline_opts_.new_widgets)
00178 gui2::new_widgets = true;
00179 if (cmdline_opts_.nocache)
00180 cache_.set_use_cache(false);
00181 if (cmdline_opts_.nodelay)
00182 game_config::no_delay = true;
00183 if (cmdline_opts_.nomusic)
00184 no_music = true;
00185 if (cmdline_opts_.nosound)
00186 no_sound = true;
00187
00188
00189
00190 if (cmdline_opts_.proxy)
00191 network::enable_connection_through_proxy();
00192 if (cmdline_opts_.proxy_address)
00193 {
00194 network::enable_connection_through_proxy();
00195 network::set_proxy_address(*cmdline_opts_.proxy_address);
00196 }
00197 if (cmdline_opts_.proxy_password)
00198 {
00199 network::enable_connection_through_proxy();
00200 network::set_proxy_password(*cmdline_opts_.proxy_password);
00201 }
00202 if (cmdline_opts_.proxy_port)
00203 {
00204 network::enable_connection_through_proxy();
00205 network::set_proxy_port(*cmdline_opts_.proxy_port);
00206 }
00207 if (cmdline_opts_.proxy_user)
00208 {
00209 network::enable_connection_through_proxy();
00210 network::set_proxy_user(*cmdline_opts_.proxy_user);
00211 }
00212 if (cmdline_opts_.resolution) {
00213 const int xres = cmdline_opts_.resolution->get<0>();
00214 const int yres = cmdline_opts_.resolution->get<1>();
00215 if(xres > 0 && yres > 0) {
00216 const std::pair<int,int> resolution(xres,yres);
00217 preferences::set_resolution(resolution);
00218 }
00219 }
00220 if (cmdline_opts_.screenshot) {
00221
00222 screenshot_map_ = *cmdline_opts_.screenshot_map_file;
00223 screenshot_filename_ = *cmdline_opts_.screenshot_output_file;
00224 no_sound = true;
00225 preferences::disable_preferences_save();
00226 }
00227 if (cmdline_opts_.server){
00228 jump_to_multiplayer_ = true;
00229
00230 if (!cmdline_opts_.server->empty())
00231 multiplayer_server_ = *cmdline_opts_.server;
00232 else
00233 {
00234 if (game_config::server_list.size() > 0)
00235 multiplayer_server_ = preferences::network_host();
00236 else
00237 multiplayer_server_ = "";
00238 }
00239 }
00240 if (cmdline_opts_.username) {
00241 preferences::disable_preferences_save();
00242 preferences::set_login(*cmdline_opts_.username);
00243 }
00244 if (cmdline_opts_.password) {
00245 preferences::disable_preferences_save();
00246 preferences::set_password(*cmdline_opts_.password);
00247 }
00248 if (cmdline_opts_.smallgui)
00249 game_config::small_gui = true;
00250 if (cmdline_opts_.test)
00251 {
00252 if (!cmdline_opts_.test->empty())
00253 test_scenario_ = *cmdline_opts_.test;
00254 }
00255 if (cmdline_opts_.validcache)
00256 cache_.set_force_valid_cache(true);
00257 if (cmdline_opts_.windowed)
00258 preferences::set_fullscreen(false);
00259 if (cmdline_opts_.with_replay)
00260 game::load_game_exception::show_replay = true;
00261
00262 std::cerr << '\n';
00263 std::cerr << "Data directory: " << game_config::path
00264 << "\nUser configuration directory: " << get_user_config_dir()
00265 << "\nUser data directory: " << get_user_data_dir()
00266 << "\nCache directory: " << get_cache_dir()
00267 << '\n';
00268
00269
00270 if (no_sound || ((preferences::sound_on() || preferences::music_on() ||
00271 preferences::turn_bell() || preferences::UI_sound_on()) &&
00272 !sound::init_sound())) {
00273 preferences::set_sound(false);
00274 preferences::set_music(false);
00275 preferences::set_turn_bell(false);
00276 preferences::set_UI_sound(false);
00277 }
00278 else if (no_music) {
00279 preferences::set_music(false);
00280 }
00281 }
00282
00283 bool game_controller::init_config(const bool force)
00284 {
00285 cache_.clear_defines();
00286
00287
00288 if (cmdline_opts_.multiplayer)
00289 cache_.add_define("MULTIPLAYER");
00290
00291 if (cmdline_opts_.test)
00292 cache_.add_define("TEST");
00293
00294 if (jump_to_editor_)
00295 cache_.add_define("EDITOR");
00296
00297 if (!cmdline_opts_.multiplayer && !cmdline_opts_.test && !jump_to_editor_)
00298 cache_.add_define("TITLE_SCREEN");
00299
00300 load_game_cfg(force);
00301
00302 game_config::load_config(game_config_.child("game_config"));
00303
00304 hotkey::deactivate_all_scopes();
00305 hotkey::set_scope_active(hotkey::SCOPE_GENERAL);
00306 hotkey::set_scope_active(hotkey::SCOPE_GAME);
00307
00308 hotkey::load_hotkeys(game_config(), true);
00309 paths_manager_.set_paths(game_config());
00310 ::init_textdomains(game_config());
00311 about::set_about(game_config());
00312 ai::configuration::init(game_config());
00313
00314 return true;
00315 }
00316
00317 bool game_controller::play_test()
00318 {
00319 static bool first_time = true;
00320
00321 if(!cmdline_opts_.test) {
00322 return true;
00323 }
00324 if(!first_time)
00325 return false;
00326
00327 first_time = false;
00328
00329 state_.classification().campaign_type = "test";
00330 state_.classification().scenario = test_scenario_;
00331 state_.classification().campaign_define = "TEST";
00332 cache_.add_define("TEST");
00333
00334 load_game_cfg();
00335
00336 paths_manager_.set_paths(game_config());
00337
00338 try {
00339 play_game(disp(),state_,game_config());
00340 } catch (game::load_game_exception &) {
00341 return true;
00342 }
00343
00344 return false;
00345 }
00346
00347 bool game_controller::play_screenshot_mode()
00348 {
00349 if(!cmdline_opts_.screenshot) {
00350 return true;
00351 }
00352
00353 cache_.clear_defines();
00354 cache_.add_define("EDITOR");
00355 load_game_cfg();
00356 const binary_paths_manager bin_paths_manager(game_config());
00357 ::init_textdomains(game_config());
00358
00359 editor::start(game_config(), video_, screenshot_map_, true, screenshot_filename_);
00360 return false;
00361 }
00362
00363 bool game_controller::play_multiplayer_mode()
00364 {
00365 state_ = game_state();
00366
00367 if(!cmdline_opts_.multiplayer) {
00368 return true;
00369 }
00370
00371 std::string era = "era_default";
00372 std::string scenario = "multiplayer_The_Freelands";
00373 std::map<int,std::string> side_types, side_controllers, side_algorithms, side_ai_configs;
00374 std::map<int,utils::string_map> side_parameters;
00375 std::string turns = "50";
00376 std::string label = "";
00377
00378 size_t sides_counted = 0;
00379
00380 if (cmdline_opts_.multiplayer_ai_config)
00381 {
00382 for(std::vector<boost::tuple<unsigned int, std::string> >::const_iterator it=cmdline_opts_.multiplayer_ai_config->begin(); it!=cmdline_opts_.multiplayer_ai_config->end(); ++it)
00383 {
00384 const unsigned int side = it->get<0>();
00385 const std::string ai_cfg_name = it->get<1>();
00386 if (side > sides_counted)
00387 {
00388 std::cerr << "counted sides: " << side << "\n";
00389 sides_counted = side;
00390 }
00391 side_ai_configs[side] = ai_cfg_name;
00392 }
00393 }
00394 if (cmdline_opts_.multiplayer_algorithm)
00395 {
00396 for(std::vector<boost::tuple<unsigned int, std::string> >::const_iterator it=cmdline_opts_.multiplayer_algorithm->begin(); it!=cmdline_opts_.multiplayer_algorithm->end(); ++it)
00397 {
00398 const unsigned int side = it->get<0>();
00399 const std::string algorithm_id = it->get<1>();
00400 if (side > sides_counted)
00401 {
00402 std::cerr << "counted sides: " << side << "\n";
00403 sides_counted = side;
00404 }
00405 side_algorithms[side] = algorithm_id;
00406 }
00407 }
00408 if (cmdline_opts_.multiplayer_controller)
00409 {
00410 for(std::vector<boost::tuple<unsigned int, std::string> >::const_iterator it=cmdline_opts_.multiplayer_controller->begin(); it!=cmdline_opts_.multiplayer_controller->end(); ++it)
00411 {
00412 const unsigned int side = it->get<0>();
00413 const std::string controller_id = it->get<1>();
00414 if (side > sides_counted)
00415 {
00416 std::cerr << "counted sides: " << side << "\n";
00417 sides_counted = side;
00418 }
00419 side_controllers[side] = controller_id;
00420 }
00421 }
00422 if (cmdline_opts_.multiplayer_era)
00423 era = *cmdline_opts_.multiplayer_era;
00424 if (cmdline_opts_.multiplayer_exit_at_end)
00425 game_config::exit_at_end = true;
00426 if (cmdline_opts_.multiplayer_label)
00427 label = *cmdline_opts_.multiplayer_label;
00428 if (cmdline_opts_.multiplayer_parm)
00429 {
00430 for(std::vector<boost::tuple<unsigned int, std::string, std::string> >::const_iterator it=cmdline_opts_.multiplayer_parm->begin(); it!=cmdline_opts_.multiplayer_parm->end(); ++it)
00431 {
00432 const unsigned int side = it->get<0>();
00433 const std::string param_name = it->get<1>();
00434 const std::string param_value = it->get<2>();
00435 side_parameters[side][param_name] = param_value;
00436 }
00437 }
00438 if (cmdline_opts_.multiplayer_scenario)
00439 scenario = *cmdline_opts_.multiplayer_scenario;
00440 if (cmdline_opts_.multiplayer_side)
00441 {
00442 for(std::vector<boost::tuple<unsigned int, std::string> >::const_iterator it=cmdline_opts_.multiplayer_side->begin(); it!=cmdline_opts_.multiplayer_side->end(); ++it)
00443 {
00444 const unsigned int side = it->get<0>();
00445 const std::string faction_id = it->get<1>();
00446 if (side > sides_counted)
00447 {
00448 std::cerr << "counted sides: " << side << "\n";
00449 sides_counted = side;
00450 }
00451 side_types[side] = faction_id;
00452 }
00453 }
00454 if (cmdline_opts_.multiplayer_turns)
00455 turns = *cmdline_opts_.multiplayer_turns;
00456
00457 const config &lvl = game_config().find_child("multiplayer", "id", scenario);
00458 if (!lvl) {
00459 std::cerr << "Could not find scenario '" << scenario << "'\n";
00460 return false;
00461 }
00462
00463 state_.classification().campaign_type = "multiplayer";
00464 state_.classification().scenario = "";
00465 state_.snapshot = config();
00466
00467 config level = lvl;
00468
00469 const config &era_cfg = game_config().find_child("era","id",era);
00470 if (!era_cfg) {
00471 std::cerr << "Could not find era '" << era << "'\n";
00472 return false;
00473 }
00474
00475 level["turns"] = turns;
00476
00477 const config &side = era_cfg.child("multiplayer_side");
00478 if (!side) {
00479 std::cerr << "Could not find multiplayer side\n";
00480 return false;
00481 }
00482
00483 while (level.child_count("side") < sides_counted) {
00484 std::cerr << "now adding side...\n";
00485 level.add_child("side");
00486 }
00487
00488 int side_num = 1;
00489 foreach (config &s, level.child_range("side"))
00490 {
00491 std::map<int,std::string>::const_iterator type = side_types.find(side_num),
00492 controller = side_controllers.find(side_num),
00493 algorithm = side_algorithms.find(side_num),
00494 ai_config = side_ai_configs.find(side_num);
00495
00496 const config* side = type == side_types.end() ?
00497 &era_cfg.find_child("multiplayer_side", "random_faction", "yes") :
00498 &era_cfg.find_child("multiplayer_side", "id", type->second);
00499
00500 if (!*side) {
00501 std::string side_name = (type == side_types.end() ? "default" : type->second);
00502 std::cerr << "Could not find side '" << side_name << "' for side " << side_num << "\n";
00503 return false;
00504 }
00505
00506 if ((*side)["random_faction"].to_bool())
00507 {
00508 std::vector<std::string> faction_choices, faction_excepts;
00509 faction_choices = utils::split((*side)["choices"]);
00510 if(faction_choices.size() == 1 && faction_choices.front() == "") {
00511 faction_choices.clear();
00512 }
00513 faction_excepts = utils::split((*side)["except"]);;
00514 if(faction_excepts.size() == 1 && faction_excepts.front() == "") {
00515 faction_excepts.clear();
00516 }
00517 unsigned j = 0;
00518 foreach (const config &faction, era_cfg.child_range("multiplayer_side"))
00519 {
00520 if (faction["random_faction"].to_bool()) continue;
00521 const std::string &faction_id = faction["id"];
00522 if (!faction_choices.empty() &&
00523 std::find(faction_choices.begin(), faction_choices.end(), faction_id) == faction_choices.end())
00524 continue;
00525 if (!faction_excepts.empty() &&
00526 std::find(faction_excepts.begin(), faction_excepts.end(), faction_id) != faction_excepts.end())
00527 continue;
00528 if (rand() % ++j == 0)
00529 side = &faction;
00530 }
00531 if ((*side)["random_faction"].to_bool()) {
00532 std::cerr << "Could not find any non-random faction for side " << side_num << "\n";
00533 return false;
00534 }
00535 std::cerr << " Faction " << (*side)["name"] <<
00536 " selected for side " << side_num << ".\n";
00537 }
00538
00539 s["side"] = side_num;
00540 s["canrecruit"] = true;
00541
00542 s.append(*side);
00543
00544 if(controller != side_controllers.end()) {
00545 s["controller"] = controller->second;
00546 }
00547
00548 if(algorithm != side_algorithms.end()) {
00549 s["ai_algorithm"] = algorithm->second;
00550 }
00551
00552 if(ai_config != side_ai_configs.end()) {
00553 s["ai_config"] = ai_config->second;
00554 }
00555
00556 config& ai_params = s.add_child("ai");
00557
00558
00559 for(utils::string_map::const_iterator j = side_parameters[side_num].begin(); j != side_parameters[side_num].end(); ++j) {
00560 s[j->first] = j->second;
00561 ai_params[j->first] = j->second;
00562 }
00563 ++side_num;
00564 }
00565 level.add_child("era", era_cfg);
00566
00567 try {
00568 recorder.add_log_data("ai_log","ai_label",label);
00569 state_.snapshot = level;
00570 play_game(disp(), state_, game_config());
00571 } catch (game::load_game_exception &) {
00572
00573 return true;
00574 } catch(twml_exception& e) {
00575 e.show(disp());
00576 return false;
00577 } catch(std::exception& e) {
00578 std::cerr << "caught exception: " << e.what() << "\n";
00579 } catch(...) {
00580 std::cerr << "caught unknown error playing level...\n";
00581 }
00582
00583 return false;
00584 }
00585
00586 bool game_controller::is_loading() const
00587 {
00588 return !game::load_game_exception::game.empty();
00589 }
00590
00591 bool game_controller::load_game()
00592 {
00593 savegame::loadgame load(disp(), game_config(), state_);
00594
00595 try {
00596 load.load_game(game::load_game_exception::game, game::load_game_exception::show_replay, game::load_game_exception::cancel_orders, game::load_game_exception::select_difficulty, game::load_game_exception::difficulty);
00597
00598 cache_.clear_defines();
00599 game_config::scoped_preproc_define dificulty_def(state_.classification().difficulty);
00600
00601 game_config::scoped_preproc_define campaign_define_def(state_.classification().campaign_define, !state_.classification().campaign_define.empty());
00602
00603 game_config::scoped_preproc_define campaign_type_def("MULTIPLAYER", state_.classification().campaign_define.empty() && (state_.classification().campaign_type == "multiplayer"));
00604
00605 typedef boost::shared_ptr<game_config::scoped_preproc_define> define_ptr;
00606 std::deque<define_ptr> extra_defines;
00607 for(std::vector<std::string>::const_iterator i = state_.classification().campaign_xtra_defines.begin(); i != state_.classification().campaign_xtra_defines.end(); ++i) {
00608 define_ptr newdefine(new game_config::scoped_preproc_define(*i));
00609 extra_defines.push_back(newdefine);
00610 }
00611
00612 try {
00613 load_game_cfg();
00614 } catch(config::error&) {
00615 cache_.clear_defines();
00616 load_game_cfg();
00617 return false;
00618 }
00619
00620 paths_manager_.set_paths(game_config());
00621 load.set_gamestate();
00622
00623 } catch(load_game_cancelled_exception&) {
00624 clear_loaded_game();
00625 return false;
00626 } catch(config::error& e) {
00627 if(e.message.empty()) {
00628 gui2::show_error_message(disp().video(), _("The file you have tried to load is corrupt"));
00629 }
00630 else {
00631 gui2::show_error_message(disp().video(), _("The file you have tried to load is corrupt: '") + e.message + '\'');
00632 }
00633 return false;
00634 } catch(twml_exception& e) {
00635 e.show(disp());
00636 return false;
00637 } catch(io_exception& e) {
00638 if(e.message.empty()) {
00639 gui2::show_error_message(disp().video(), _("File I/O Error while reading the game"));
00640 } else {
00641 gui2::show_error_message(disp().video(), _("File I/O Error while reading the game: '") + e.message + '\'');
00642 }
00643 return false;
00644 } catch(game::error& e) {
00645 if(e.message.empty()) {
00646 gui2::show_error_message(disp().video(), _("The file you have tried to load is corrupt"));
00647 }
00648 else {
00649 gui2::show_error_message(disp().video(), _("The file you have tried to load is corrupt: '") + e.message + '\'');
00650 }
00651 return false;
00652 }
00653 recorder = replay(state_.replay_data);
00654 recorder.start_replay();
00655 recorder.set_skip(false);
00656
00657 LOG_CONFIG << "has snapshot: " << (state_.snapshot.child("side") ? "yes" : "no") << "\n";
00658
00659 if (!state_.snapshot.child("side")) {
00660
00661 if (load.show_replay()) {
00662
00663
00664 LOG_CONFIG << "replaying (start of scenario)\n";
00665 } else {
00666 LOG_CONFIG << "skipping...\n";
00667 recorder.set_skip(false);
00668 }
00669 } else {
00670
00671 if(load.show_replay()) {
00672 statistics::clear_current_scenario();
00673 LOG_CONFIG << "replaying (snapshot)\n";
00674 } else {
00675 LOG_CONFIG << "setting replay to end...\n";
00676 recorder.set_to_end();
00677 if(!recorder.at_end()) {
00678 WRN_CONFIG << "recorder is not at the end!!!\n";
00679 }
00680 }
00681 }
00682
00683 if(state_.classification().campaign_type == "multiplayer") {
00684 foreach (config &side, state_.snapshot.child_range("side"))
00685 {
00686 if (side["controller"] == "network")
00687 side["controller"] = "human";
00688 if (side["controller"] == "network_ai")
00689 side["controller"] = "human_ai";
00690 }
00691 }
00692
00693 if (load.cancel_orders()) {
00694 foreach (config &side, state_.snapshot.child_range("side"))
00695 {
00696 if (side["controller"] != "human") continue;
00697 foreach (config &unit, side.child_range("unit"))
00698 {
00699 unit["goto_x"] = -999;
00700 unit["goto_y"] = -999;
00701 }
00702 }
00703 }
00704
00705 return true;
00706 }
00707
00708 void game_controller::set_tutorial()
00709 {
00710 state_ = game_state();
00711 state_.classification().campaign_type = "tutorial";
00712 state_.classification().scenario = "tutorial";
00713 state_.classification().campaign_define = "TUTORIAL";
00714 cache_.clear_defines();
00715 cache_.add_define("TUTORIAL");
00716
00717 }
00718
00719 void game_controller::mark_completed_campaigns(std::vector<config> &campaigns)
00720 {
00721 foreach (config &campaign, campaigns) {
00722 campaign["completed"] = preferences::is_campaign_completed(campaign["id"]);
00723 }
00724 }
00725
00726 bool game_controller::new_campaign()
00727 {
00728 state_ = game_state();
00729 state_.classification().campaign_type = "scenario";
00730
00731 const config::const_child_itors &ci = game_config().child_range("campaign");
00732 std::vector<config> campaigns(ci.first, ci.second);
00733 mark_completed_campaigns(campaigns);
00734 std::stable_sort(campaigns.begin(),campaigns.end(),less_campaigns_rank);
00735
00736 if(campaigns.begin() == campaigns.end()) {
00737 gui2::show_error_message(disp().video(),
00738 _("No campaigns are available.\n"));
00739 return false;
00740 }
00741
00742 int campaign_num = -1;
00743
00744 if (jump_to_campaign_.campaign_id_.empty() == true)
00745 {
00746 gui2::tcampaign_selection dlg(campaigns);
00747
00748 try {
00749 dlg.show(disp().video());
00750 } catch(twml_exception& e) {
00751 e.show(disp());
00752 return false;
00753 }
00754
00755 if(dlg.get_retval() != gui2::twindow::OK) {
00756 return false;
00757 }
00758
00759 campaign_num = dlg.get_choice();
00760 }
00761 else
00762 {
00763
00764
00765
00766
00767 for(size_t i = 0; i < campaigns.size(); ++i)
00768 {
00769 if (campaigns[i]["id"] == jump_to_campaign_.campaign_id_)
00770 {
00771 campaign_num = i;
00772 break;
00773 }
00774 }
00775
00776
00777 if (campaign_num == -1)
00778 {
00779 std::cerr<<"No such campaign id to jump to: ["<<jump_to_campaign_.campaign_id_<<"]\n";
00780 return false;
00781 }
00782 }
00783
00784 const config &campaign = campaigns[campaign_num];
00785 state_.classification().campaign = campaign["id"].str();
00786 state_.classification().abbrev = campaign["abbrev"].str();
00787
00788
00789 if (jump_to_campaign_.scenario_id_.empty())
00790 state_.classification().scenario = campaign["first_scenario"].str();
00791 else
00792 state_.classification().scenario = jump_to_campaign_.scenario_id_;
00793
00794 state_.classification().end_text = campaign["end_text"].str();
00795 state_.classification().end_text_duration = campaign["end_text_duration"];
00796
00797 const std::string difficulty_descriptions = campaign["difficulty_descriptions"];
00798 std::vector<std::string> difficulty_options = utils::split(difficulty_descriptions, ';');
00799
00800 const std::vector<std::string> difficulties = utils::split(campaign["difficulties"]);
00801
00802 if(difficulties.empty() == false) {
00803 int difficulty = 0;
00804 if (jump_to_campaign_.difficulty_ == -1){
00805 if(difficulty_options.size() != difficulties.size()) {
00806 difficulty_options.resize(difficulties.size());
00807 std::copy(difficulties.begin(),difficulties.end(),difficulty_options.begin());
00808 }
00809
00810 gui2::tcampaign_difficulty dlg(difficulty_options);
00811 dlg.show(disp().video());
00812
00813 if(dlg.selected_index() == -1) {
00814 if (jump_to_campaign_.campaign_id_.empty() == false)
00815 {
00816 jump_to_campaign_.campaign_id_ = "";
00817 }
00818
00819 return new_campaign();
00820 }
00821 difficulty = dlg.selected_index();
00822 }
00823 else
00824 {
00825 if (jump_to_campaign_.difficulty_
00826 > static_cast<int>(difficulties.size()))
00827 {
00828 std::cerr << "incorrect difficulty number: [" <<
00829 jump_to_campaign_.difficulty_ << "]. maximum is [" <<
00830 difficulties.size() << "].\n";
00831 return false;
00832 }
00833 else
00834 {
00835 difficulty = jump_to_campaign_.difficulty_ - 1;
00836 }
00837 }
00838
00839 state_.classification().difficulty = difficulties[difficulty];
00840 cache_.clear_defines();
00841 cache_.add_define(difficulties[difficulty]);
00842 } else {
00843
00844 cache_.clear_defines();
00845 }
00846
00847 state_.classification().campaign_define = campaign["define"].str();
00848 state_.classification().campaign_xtra_defines = utils::split(campaign["extra_defines"]);
00849
00850 return true;
00851 }
00852
00853 std::string game_controller::jump_to_campaign_id() const
00854 {
00855 return jump_to_campaign_.campaign_id_;
00856 }
00857
00858 bool game_controller::goto_campaign()
00859 {
00860 if(jump_to_campaign_.jump_){
00861 if(new_campaign()) {
00862 jump_to_campaign_.jump_ = false;
00863 launch_game(game_controller::RELOAD_DATA);
00864 }else{
00865 jump_to_campaign_.jump_ = false;
00866 return false;
00867 }
00868 }
00869 return true;
00870 }
00871
00872 bool game_controller::goto_multiplayer()
00873 {
00874 if(jump_to_multiplayer_){
00875 jump_to_multiplayer_ = false;
00876 if(play_multiplayer()){
00877 ;
00878 }else{
00879 return false;
00880 }
00881 }
00882 return true;
00883 }
00884
00885 bool game_controller::goto_editor()
00886 {
00887 if(jump_to_editor_){
00888 jump_to_editor_ = false;
00889 if (start_editor(normalize_path(game::load_game_exception::game)) ==
00890 editor::EXIT_QUIT_TO_DESKTOP)
00891 {
00892 return false;
00893 }
00894 clear_loaded_game();
00895 }
00896 return true;
00897 }
00898
00899 void game_controller::reload_changed_game_config()
00900 {
00901
00902 refresh_addon_version_info_cache();
00903
00904
00905 cache_.recheck_filetree_checksum();
00906 old_defines_map_.clear();
00907 clear_binary_paths_cache();
00908 init_config(true);
00909 }
00910
00911 void game_controller::start_wesnothd()
00912 {
00913 const std::string wesnothd_program =
00914 preferences::get_mp_server_program_name().empty() ?
00915 get_program_invocation("wesnothd") : preferences::get_mp_server_program_name();
00916
00917 std::string config = get_user_config_dir() + "/lan_server.cfg";
00918 if (!file_exists(config)) {
00919
00920 write_file(config, read_file(get_wml_location("lan_server.cfg")));
00921 }
00922
00923 #ifndef _WIN32
00924 std::string command = "\"" + wesnothd_program +"\" -c \"" + config + "\" -d -t 2 -T 5";
00925 #else
00926
00927 std::string command = "cmd /C start \"wesnoth server\" /B \"" + wesnothd_program + "\" -c \"" + config + "\" -t 2 -T 5";
00928 #endif
00929 LOG_GENERAL << "Starting wesnothd: "<< command << "\n";
00930 if (std::system(command.c_str()) == 0) {
00931
00932 SDL_Delay(50);
00933 return;
00934 }
00935 preferences::set_mp_server_program_name("");
00936
00937
00938 WRN_GENERAL << "Failed to run server start script\n";
00939 throw game::mp_server_error("Starting MP server failed!");
00940 }
00941
00942 bool game_controller::play_multiplayer()
00943 {
00944 int res;
00945
00946 state_ = game_state();
00947 state_.classification().campaign_type = "multiplayer";
00948 state_.classification().campaign_define = "MULTIPLAYER";
00949
00950
00951 if( multiplayer_server_.empty() ){
00952
00953 int start_server;
00954 do {
00955 start_server = 0;
00956
00957 gui2::tmp_method_selection dlg;
00958
00959 dlg.show(disp().video());
00960
00961 if(dlg.get_retval() == gui2::twindow::OK) {
00962 res = dlg.get_choice();
00963 } else {
00964 return false;
00965
00966 }
00967
00968 if (res == 2 && preferences::mp_server_warning_disabled() < 2) {
00969 start_server = !gui2::tmp_host_game_prompt::execute(disp().video());
00970 }
00971 } while (start_server);
00972 if (res < 0) {
00973 return false;
00974 }
00975
00976 }else{
00977 res = 4;
00978 }
00979
00980 try {
00981 if (res == 2)
00982 {
00983 try {
00984 start_wesnothd();
00985 } catch(game::mp_server_error&)
00986 {
00987 std::string path = preferences::show_wesnothd_server_search(disp());
00988
00989 if (!path.empty())
00990 {
00991 preferences::set_mp_server_program_name(path);
00992 start_wesnothd();
00993 }
00994 else
00995 {
00996 return false;
00997 }
00998 }
00999
01000
01001 }
01002
01003 {
01004 cache_.clear_defines();
01005 game_config::scoped_preproc_define multiplayer(state_.classification().campaign_define);
01006 load_game_cfg();
01007 events::discard(INPUT_MASK);
01008 cursor::set(cursor::NORMAL);
01009
01010 paths_manager_.set_paths(game_config());
01011 clear_binary_paths_cache();
01012 }
01013
01014 if(res == 3) {
01015 std::vector<std::string> chat;
01016 config game_data;
01017
01018 const mp::controller cntr = mp::CNTR_LOCAL;
01019
01020 mp::start_local_game(disp(), game_config(), cntr);
01021
01022 } else if((res >= 0 && res <= 2) || res == 4) {
01023 std::string host;
01024 if(res == 0) {
01025 host = preferences::server_list().front().address;
01026 }else if(res == 2) {
01027 host = "localhost";
01028 }else if(res == 4){
01029 host = multiplayer_server_;
01030 multiplayer_server_ = "";
01031 }
01032 mp::start_client(disp(), game_config(), host);
01033 }
01034
01035 } catch(game::mp_server_error& e) {
01036 gui2::show_error_message(disp().video(), _("Error while starting server: ") + e.message);
01037 } catch(game::load_game_failed& e) {
01038 gui2::show_error_message(disp().video(), _("The game could not be loaded: ") + e.message);
01039 } catch(game::game_error& e) {
01040 gui2::show_error_message(disp().video(), _("Error while playing the game: ") + e.message);
01041 } catch(network::error& e) {
01042 if(e.message != "") {
01043 ERR_NET << "caught network::error: " << e.message << "\n";
01044 gui2::show_transient_message(disp().video()
01045 , ""
01046 , gettext(e.message.c_str()));
01047 } else {
01048 ERR_NET << "caught network::error\n";
01049 }
01050 } catch(config::error& e) {
01051 if(e.message != "") {
01052 ERR_CONFIG << "caught config::error: " << e.message << "\n";
01053 gui2::show_transient_message(disp().video(), "", e.message);
01054 } else {
01055 ERR_CONFIG << "caught config::error\n";
01056 }
01057 } catch(incorrect_map_format_error& e) {
01058 gui2::show_error_message(disp().video(), std::string(_("The game map could not be loaded: ")) + e.message);
01059 } catch (game::load_game_exception &) {
01060
01061 } catch(twml_exception& e) {
01062 e.show(disp());
01063 }
01064
01065 return false;
01066 }
01067
01068 bool game_controller::change_language()
01069 {
01070 gui2::tlanguage_selection dlg;
01071 dlg.show(disp().video());
01072 if (dlg.get_retval() != gui2::twindow::OK) return false;
01073
01074 if (!cmdline_opts_.nogui) {
01075 std::string wm_title_string = _("The Battle for Wesnoth");
01076 wm_title_string += " - " + game_config::revision;
01077 SDL_WM_SetCaption(wm_title_string.c_str(), NULL);
01078 }
01079
01080 return true;
01081 }
01082
01083 void game_controller::show_preferences()
01084 {
01085 const preferences::display_manager disp_manager(&disp());
01086 preferences::show_preferences_dialog(disp(),game_config());
01087
01088 disp().redraw_everything();
01089 }
01090
01091 void game_controller::set_unit_data()
01092 {
01093 loadscreen::start_stage("load unit types");
01094 if (config &units = game_config_.child("units")) {
01095 unit_types.set_config(units);
01096 }
01097 }
01098
01099 void game_controller::load_game_cfg(const bool force)
01100 {
01101
01102
01103 if (game_config::debug || game_config::mp_debug) {
01104 cache_.add_define("DEBUG_MODE");
01105 }
01106
01107 if (!game_config_.empty() && !force
01108 && old_defines_map_ == cache_.get_preproc_map())
01109 return;
01110 old_defines_map_ = cache_.get_preproc_map();
01111 loadscreen::global_loadscreen_manager loadscreen_manager(disp().video());
01112 cursor::setter cur(cursor::WAIT);
01113
01114
01115 try {
01116
01117
01118
01119
01120
01121
01122 loadscreen::start_stage("verify cache");
01123 data_tree_checksum();
01124 loadscreen::start_stage("create cache");
01125
01126
01127 game_config::config_cache_transaction main_transaction;
01128
01129 cache_.get_config(game_config::path +"/data", game_config_);
01130
01131 main_transaction.lock();
01132
01133
01134
01135 config core_terrain_rules;
01136 core_terrain_rules.splice_children(game_config_, "terrain_graphics");
01137
01138
01139 const std::string user_campaign_dir = get_addon_campaigns_dir();
01140 std::vector< std::string > error_addons;
01141
01142 std::vector<std::string> user_dirs;
01143
01144 std::vector<std::string> user_files;
01145
01146
01147 std::vector<std::string> addons_to_load;
01148
01149 get_files_in_dir(user_campaign_dir,&user_files,&user_dirs,ENTIRE_FILE_PATH);
01150 std::string user_error_log;
01151
01152
01153 for(std::vector<std::string>::const_iterator uc = user_files.begin(); uc != user_files.end(); ++uc) {
01154 const std::string file = *uc;
01155 int size_minus_extension = file.size() - 4;
01156 if(file.substr(size_minus_extension, file.size()) == ".cfg") {
01157
01158
01159 if(file_exists(file.substr(0, size_minus_extension)))
01160 lg::wml_error << '\'' << file << "' is deprecated, use '" << file.substr(0, size_minus_extension) << "/_main.cfg' instead.\n";
01161 addons_to_load.push_back(file);
01162 }
01163 }
01164
01165
01166 for(std::vector<std::string>::const_iterator uc = user_dirs.begin(); uc != user_dirs.end(); ++uc){
01167 const std::string main_cfg = *uc + "/_main.cfg";
01168 if (file_exists(main_cfg))
01169 addons_to_load.push_back(main_cfg);
01170 }
01171
01172
01173 for(std::vector<std::string>::const_iterator uc = addons_to_load.begin(); uc != addons_to_load.end(); ++uc) {
01174 const std::string toplevel = *uc;
01175 try {
01176 config umc_cfg;
01177 cache_.get_config(toplevel, umc_cfg);
01178
01179 game_config_.append(umc_cfg);
01180 } catch(config::error& err) {
01181 ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
01182 error_addons.push_back(*uc);
01183 user_error_log += err.message + "\n";
01184 } catch(preproc_config::error& err) {
01185 ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
01186 error_addons.push_back(*uc);
01187 user_error_log += err.message + "\n";
01188 } catch(io_exception&) {
01189 ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
01190 error_addons.push_back(*uc);
01191 }
01192 if(error_addons.empty() == false) {
01193 std::stringstream msg;
01194 msg << _n("The following add-on had errors and could not be loaded:",
01195 "The following add-ons had errors and could not be loaded:",
01196 error_addons.size());
01197 for(std::vector<std::string>::const_iterator i = error_addons.begin(); i != error_addons.end(); ++i) {
01198 msg << "\n" << *i;
01199 }
01200
01201 msg << '\n' << _("ERROR DETAILS:") << '\n' << user_error_log;
01202
01203 gui2::show_error_message(disp().video(),msg.str());
01204 }
01205 }
01206
01207
01208 extract_preload_scripts(game_config_);
01209 game_config_.clear_children("lua");
01210
01211 config colorsys_info;
01212 colorsys_info.splice_children(game_config_, "color_range");
01213 colorsys_info.splice_children(game_config_, "color_palette");
01214
01215 game_config_.merge_children("units");
01216 game_config_.splice_children(core_terrain_rules, "terrain_graphics");
01217
01218 config& hashes = game_config_.add_child("multiplayer_hashes");
01219 foreach (const config &ch, game_config_.child_range("multiplayer")) {
01220 hashes[ch["id"]] = ch.hash();
01221 }
01222
01223 game_config::add_color_info(colorsys_info);
01224
01225 set_unit_data();
01226
01227 terrain_builder::set_terrain_rules_cfg(game_config());
01228
01229 ::init_strings(game_config());
01230
01231 theme::set_known_themes(&game_config());
01232
01233 } catch(game::error& e) {
01234 ERR_CONFIG << "Error loading game configuration files\n";
01235 gui2::show_error_message(disp().video(), _("Error loading game configuration files: '") +
01236 e.message + _("' (The game will now exit)"));
01237 throw;
01238 }
01239 }
01240
01241 void game_controller::launch_game(RELOAD_GAME_DATA reload)
01242 {
01243 loadscreen::global_loadscreen_manager loadscreen_manager(disp().video());
01244 loadscreen::start_stage("load data");
01245 if(reload == RELOAD_DATA) {
01246 game_config::scoped_preproc_define campaign_define(state_.classification().campaign_define, state_.classification().campaign_define.empty() == false);
01247
01248 typedef boost::shared_ptr<game_config::scoped_preproc_define> define_ptr;
01249 std::deque<define_ptr> extra_defines;
01250 for(std::vector<std::string>::const_iterator i = state_.classification().campaign_xtra_defines.begin(); i != state_.classification().campaign_xtra_defines.end(); ++i) {
01251 define_ptr newdefine(new game_config::scoped_preproc_define(*i));
01252 extra_defines.push_back(newdefine);
01253 }
01254 try {
01255 load_game_cfg();
01256 } catch(config::error&) {
01257 cache_.clear_defines();
01258 load_game_cfg();
01259 return;
01260 }
01261 }
01262
01263 const binary_paths_manager bin_paths_manager(game_config());
01264
01265 try {
01266 const LEVEL_RESULT result = play_game(disp(),state_,game_config());
01267
01268
01269 if(result == VICTORY && (state_.classification().campaign_type.empty() || state_.classification().campaign_type != "multiplayer")) {
01270 preferences::add_completed_campaign(state_.classification().campaign);
01271 the_end(disp(), state_.classification().end_text, state_.classification().end_text_duration);
01272 if(state_.classification().end_credits) {
01273 about::show_about(disp(),state_.classification().campaign);
01274 }
01275 }
01276
01277 clear_loaded_game();
01278 } catch (game::load_game_exception &) {
01279
01280 } catch(twml_exception& e) {
01281 e.show(disp());
01282 }
01283 }
01284
01285 void game_controller::play_replay()
01286 {
01287 const binary_paths_manager bin_paths_manager(game_config());
01288
01289 try {
01290 ::play_replay(disp(),state_,game_config(),video_);
01291
01292 clear_loaded_game();
01293 } catch (game::load_game_exception &) {
01294
01295 } catch(twml_exception& e) {
01296 e.show(disp());
01297 }
01298 }
01299
01300 editor::EXIT_STATUS game_controller::start_editor(const std::string& filename)
01301 {
01302 while(true){
01303 cache_.clear_defines();
01304 cache_.add_define("EDITOR");
01305 load_game_cfg();
01306 const binary_paths_manager bin_paths_manager(game_config());
01307 ::init_textdomains(game_config());
01308
01309 editor::EXIT_STATUS res = editor::start(game_config(), video_, filename);
01310
01311 if(res != editor::EXIT_RELOAD_DATA)
01312 return res;
01313
01314 reload_changed_game_config();
01315 image::flush_cache();
01316 }
01317 return editor::EXIT_ERROR;
01318 }
01319
01320 game_controller::~game_controller()
01321 {
01322 delete gui::empty_menu;
01323 sound::close_sound();
01324 }