00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "global.hpp"
00016
00017 #include "SDL.h"
00018 #include "SDL_mixer.h"
00019
00020 #include "about.hpp"
00021 #include "config.hpp"
00022 #include "construct_dialog.hpp"
00023 #include "cursor.hpp"
00024 #include "dialogs.hpp"
00025 #include "game_display.hpp"
00026 #include "filesystem.hpp"
00027 #include "font.hpp"
00028 #include "game_config.hpp"
00029 #include "game_errors.hpp"
00030 #include "gamestatus.hpp"
00031 #include "gettext.hpp"
00032 #include "gui/dialogs/addon_connect.hpp"
00033 #include "gui/dialogs/language_selection.hpp"
00034 #include "gui/dialogs/mp_method_selection.hpp"
00035 #include "gui/widgets/button.hpp"
00036 #include "help.hpp"
00037 #include "hotkeys.hpp"
00038 #include "intro.hpp"
00039 #include "language.hpp"
00040 #include "loadscreen.hpp"
00041 #include "log.hpp"
00042 #include "widgets/menu.hpp"
00043 #include "marked-up_text.hpp"
00044 #include "multiplayer.hpp"
00045 #include "network.hpp"
00046 #include "playcampaign.hpp"
00047 #include "preferences_display.hpp"
00048 #include "publish_campaign.hpp"
00049 #include "replay.hpp"
00050 #include "sound.hpp"
00051 #include "statistics.hpp"
00052 #include "thread.hpp"
00053 #include "titlescreen.hpp"
00054 #include "util.hpp"
00055 #include "upload_log.hpp"
00056 #include "wml_exception.hpp"
00057 #include "wml_separators.hpp"
00058 #include "serialization/binary_or_text.hpp"
00059 #include "serialization/binary_wml.hpp"
00060 #include "serialization/parser.hpp"
00061 #include "serialization/preprocessor.hpp"
00062 #include "serialization/string_utils.hpp"
00063 #include "sha1.hpp"
00064
00065 #ifdef HAVE_PYTHON
00066 #include "ai_python.hpp"
00067 #endif
00068
00069 #include "wesconfig.h"
00070
00071 #include <clocale>
00072 #include <cmath>
00073 #include <cstdlib>
00074 #include <ctime>
00075 #include <fstream>
00076 #include <iostream>
00077 #include <iterator>
00078 #include <sstream>
00079 #include <string>
00080
00081 #include <boost/iostreams/copy.hpp>
00082 #include <boost/iostreams/filtering_streambuf.hpp>
00083 #include <boost/iostreams/filter/gzip.hpp>
00084
00085 #define ERR_CONFIG LOG_STREAM(err, config)
00086 #define WRN_CONFIG LOG_STREAM(warn, config)
00087 #define DBG_CONFIG LOG_STREAM(debug, config)
00088 #define LOG_CONFIG LOG_STREAM(info, config)
00089 #define LOG_GENERAL LOG_STREAM(info, general)
00090 #define DBG_GENERAL LOG_STREAM(debug, general)
00091 #define ERR_NET LOG_STREAM(err, network)
00092 #define LOG_NET LOG_STREAM(info, network)
00093 #define ERR_FS LOG_STREAM(err, filesystem)
00094
00095 static bool less_campaigns_rank(const config* a, const config* b) {
00096 return lexical_cast_default<int>((*a)["rank"],1000) <
00097 lexical_cast_default<int>((*b)["rank"],1000);
00098 }
00099
00100 namespace {
00101
00102 static bool new_widgets = false;
00103
00104 class game_controller
00105 {
00106 public:
00107 game_controller(int argc, char** argv);
00108 ~game_controller();
00109
00110 game_display& disp();
00111
00112 bool init_video();
00113 bool init_config();
00114 bool init_language();
00115 bool play_test();
00116 bool play_multiplayer_mode();
00117
00118 void reset_game_cfg();
00119 void reset_defines_map();
00120 void reload_changed_game_config();
00121 void read_configs(std::string&);
00122
00123 bool is_loading() const;
00124 bool load_game();
00125 void set_tutorial();
00126
00127 bool new_campaign();
00128 bool goto_campaign();
00129 bool goto_multiplayer();
00130 bool play_multiplayer();
00131 void manage_addons();
00132 void download_campaigns(std::string host);
00133 bool change_language();
00134
00135 void show_help();
00136 void show_preferences();
00137 void show_upload_begging();
00138
00139 enum RELOAD_GAME_DATA { RELOAD_DATA, NO_RELOAD_DATA };
00140 void play_game(RELOAD_GAME_DATA reload=RELOAD_DATA);
00141 void play_replay();
00142 const config& game_config(){return game_config_;};
00143
00144 private:
00145 game_controller(const game_controller&);
00146 void operator=(const game_controller&);
00147
00148 void read_game_cfg(bool use_cache);
00149 void refresh_game_cfg(bool reset_translations=false);
00150 void set_unit_data();
00151
00152 void upload_campaign(const std::string& campaign, network::connection sock);
00153 void delete_campaign(const std::string& campaign, network::connection sock);
00154 void remove_campaign(const std::string& campaign);
00155
00156 const int argc_;
00157 int arg_;
00158 const char* const * const argv_;
00159
00160
00161
00162 const threading::manager thread_manager;
00163
00164 CVideo video_;
00165
00166 const font::manager font_manager_;
00167 const preferences::manager prefs_manager_;
00168 const image::manager image_manager_;
00169 const events::event_context main_event_context_;
00170 const hotkey::manager hotkey_manager_;
00171 const upload_log::manager upload_log_manager_;
00172 sound::music_thinker music_thinker_;
00173 resize_monitor resize_monitor_;
00174 binary_paths_manager paths_manager_;
00175
00176 std::string test_scenario_;
00177
00178 bool test_mode_, multiplayer_mode_, no_gui_;
00179 bool use_caching_;
00180 bool force_valid_cache_;
00181 int force_bpp_;
00182
00183 config game_config_;
00184
00185 util::scoped_ptr<game_display> disp_;
00186
00187 game_state state_;
00188
00189 std::string loaded_game_;
00190 bool loaded_game_show_replay_;
00191 bool loaded_game_cancel_orders_;
00192
00193 preproc_map defines_map_, old_defines_map_;
00194
00195 std::string multiplayer_server_;
00196 bool jump_to_campaign_, jump_to_multiplayer_;
00197 };
00198
00199 game_controller::game_controller(int argc, char** argv)
00200 : argc_(argc), arg_(1), argv_(argv), thread_manager(),
00201 test_scenario_("test"), test_mode_(false), multiplayer_mode_(false),
00202 no_gui_(false), use_caching_(true), force_valid_cache_(false),
00203 force_bpp_(-1), disp_(NULL), loaded_game_show_replay_(false),
00204 loaded_game_cancel_orders_(false),
00205 jump_to_campaign_(false), jump_to_multiplayer_(false)
00206 {
00207 bool no_sound = false;
00208 for(arg_ = 1; arg_ != argc_; ++arg_) {
00209 const std::string val(argv_[arg_]);
00210 if(val.empty()) {
00211 continue;
00212 }
00213
00214 if(val == "--fps") {
00215 preferences::set_show_fps(true);
00216 } else if(val == "--nocache") {
00217 use_caching_ = false;
00218 } else if(val == "--max-fps") {
00219 if(arg_+1 != argc_) {
00220 ++arg_;
00221 int fps = lexical_cast_default<int>(argv_[arg_], 50);
00222 fps = minimum<int>(fps, 1000);
00223 fps = maximum<int>(fps, 1);
00224 fps = 1000 / fps;
00225
00226 if(1000 % fps != 0) {
00227 ++fps;
00228 }
00229 preferences::set_draw_delay(fps);
00230 }
00231 } else if(val == "--validcache") {
00232 force_valid_cache_ = true;
00233 } else if(val == "--resolution" || val == "-r") {
00234 if(arg_+1 != argc_) {
00235 ++arg_;
00236 const std::string val(argv_[arg_]);
00237 const std::vector<std::string> res = utils::split(val, 'x');
00238 if(res.size() == 2) {
00239 const int xres = lexical_cast_default<int>(res.front());
00240 const int yres = lexical_cast_default<int>(res.back());
00241 if(xres > 0 && yres > 0) {
00242 const std::pair<int,int> resolution(xres,yres);
00243 preferences::set_resolution(resolution);
00244 }
00245 }
00246 }
00247 } else if(val == "--bpp") {
00248 if(arg_+1 != argc_) {
00249 ++arg_;
00250 force_bpp_ = lexical_cast_default<int>(argv_[arg_],-1);
00251 }
00252 } else if(val == "--load" || val == "-l") {
00253 if(arg_+1 != argc_) {
00254 ++arg_;
00255 loaded_game_ = argv_[arg_];
00256 }
00257 } else if(val == "--with-replay") {
00258 loaded_game_show_replay_ = true;
00259
00260 } else if(val == "--nogui") {
00261 no_gui_ = true;
00262 no_sound = true;
00263 preferences::disable_preferences_save();
00264 } else if(val == "--windowed" || val == "-w") {
00265 preferences::set_fullscreen(false);
00266 } else if(val == "--fullscreen" || val == "-f") {
00267 preferences::set_fullscreen(true);
00268
00269 } else if(val == "--campaign" || val == "-c") {
00270 jump_to_campaign_ = true;
00271
00272 } else if(val == "--server" || val == "-s"){
00273 jump_to_multiplayer_ = true;
00274
00275 if(argc_ > arg_+1){
00276 multiplayer_server_ = argv_[arg_+1];
00277 ++arg_;
00278
00279 }else{
00280 if(game_config::server_list.size() > 0)
00281 multiplayer_server_ = preferences::network_host();
00282 else
00283 multiplayer_server_ = "";
00284 }
00285
00286 } else if(val == "--multiplayer" || val == "-m") {
00287 multiplayer_mode_ = true;
00288 break;
00289 } else if(val == "--test" || val == "-t") {
00290 test_mode_ = true;
00291
00292
00293
00294 if(arg_ + 2 < argc_ && argv_[arg_ + 1][0] != '-') {
00295 ++arg_;
00296 test_scenario_ = argv_[arg_];
00297 }
00298 } else if(val == "--debug" || val == "-d") {
00299 game_config::debug = true;
00300 game_config::mp_debug = true;
00301 } else if(val == "--no-delay") {
00302 game_config::no_delay = true;
00303 } else if (val.substr(0, 6) == "--log-") {
00304 } else if(val == "--nosound") {
00305 no_sound = true;
00306 } else if(val == "--new-widgets") {
00307
00308 new_widgets = true;
00309 } else if(val[0] == '-') {
00310 std::cerr << "unknown option: " << val << std::endl;
00311 throw config::error("unknown option");
00312 } else {
00313
00314 std::cerr << "Setting path using " << val << std::endl;
00315 if(val[0] == '/') {
00316 game_config::path = val;
00317 } else {
00318 game_config::path = get_cwd() + '/' + val;
00319 }
00320
00321 if(!is_directory(game_config::path)) {
00322 std::cerr << "Could not find directory '" << game_config::path << "'\n";
00323 throw config::error("directory not found");
00324 }
00325
00326 }
00327 }
00328 std::cerr << "Data at '" << game_config::path << "'\n";
00329
00330
00331 if (no_sound || ((preferences::sound_on() || preferences::music_on() ||
00332 preferences::turn_bell() || preferences::UI_sound_on()) &&
00333 !sound::init_sound())) {
00334 preferences::set_sound(false);
00335 preferences::set_music(false);
00336 preferences::set_turn_bell(false);
00337 preferences::set_UI_sound(false);
00338 }
00339 }
00340
00341 game_display& game_controller::disp()
00342 {
00343 if(disp_.get() == NULL) {
00344
00345 if(get_video_surface() == NULL) {
00346 throw CVideo::error();
00347 }
00348
00349 static unit_map dummy_umap;
00350 static config dummy_cfg;
00351 static gamemap dummy_map(dummy_cfg, "");
00352 static gamestatus dummy_status(dummy_cfg, 0);
00353 static std::vector<team> dummy_teams;
00354 disp_.assign(new game_display(dummy_umap, video_, dummy_map, dummy_status,
00355 dummy_teams, dummy_cfg, dummy_cfg, dummy_cfg));
00356 }
00357
00358 return *disp_.get();
00359 }
00360
00361 bool game_controller::init_video()
00362 {
00363 if(no_gui_) {
00364 if(!multiplayer_mode_) {
00365 std::cerr << "--nogui flag is only valid with --multiplayer flag\n";
00366 return false;
00367 }
00368 video_.make_fake();
00369 game_config::no_delay = true;
00370 return true;
00371 }
00372
00373 image::set_wm_icon();
00374
00375 int video_flags = preferences::fullscreen() ? FULL_SCREEN : 0;
00376
00377 std::pair<int,int> resolution = preferences::resolution();
00378
00379 int DefaultBPP = 24;
00380 const SDL_VideoInfo* const video_info = SDL_GetVideoInfo();
00381 if(video_info != NULL && video_info->vfmt != NULL) {
00382 DefaultBPP = video_info->vfmt->BitsPerPixel;
00383 }
00384
00385 std::cerr << "Checking video mode: " << resolution.first
00386 << "x" << resolution.second << "x" << DefaultBPP << "...\n";
00387 int bpp = video_.modePossible(resolution.first,resolution.second,DefaultBPP,video_flags);
00388
00389 if(bpp == 0) {
00390
00391 std::cerr << "Video mode " << resolution.first
00392 << "x" << resolution.second << "x" << DefaultBPP << " "
00393 << "is not supported - attempting 1024x768x" << DefaultBPP << "...\n";
00394
00395
00396 resolution.first = 1024;
00397 resolution.second = 768;
00398
00399 bpp = video_.modePossible(resolution.first,resolution.second,DefaultBPP,video_flags);
00400
00401 if(bpp == 0) {
00402 std::cerr << "1024x768x" << DefaultBPP << " not available - attempting 800x600x" << DefaultBPP << "...\n";
00403
00404 resolution.first = 800;
00405 resolution.second = 600;
00406
00407 bpp = video_.modePossible(resolution.first,resolution.second,DefaultBPP,video_flags);
00408 }
00409
00410 #ifdef USE_TINY_GUI
00411 if(bpp == 0) {
00412 std::cerr << "800x600x" << DefaultBPP << " not available - attempting 640x480x" << DefaultBPP << "...\n";
00413
00414 resolution.first = 640;
00415 resolution.second = 480;
00416
00417 bpp = video_.modePossible(resolution.first,resolution.second,DefaultBPP,video_flags);
00418 }
00419
00420 if(bpp == 0) {
00421 std::cerr << "640x480x" << DefaultBPP << " not available - attempting 320x240x" << DefaultBPP << "...\n";
00422
00423 resolution.first = 320;
00424 resolution.second = 240;
00425
00426 bpp = video_.modePossible(resolution.first,resolution.second,DefaultBPP,video_flags);
00427 }
00428 #endif
00429
00430 #ifdef USE_SMALL_GUI
00431 if(bpp == 0) {
00432 std::cerr << "800x600x" << DefaultBPP << " not available - attempting 800x480x" << DefaultBPP << "...\n";
00433
00434 resolution.first = 800;
00435 resolution.second = 480;
00436
00437 bpp = video_.modePossible(resolution.first,resolution.second,DefaultBPP,video_flags);
00438 }
00439 #endif
00440
00441 if(bpp == 0) {
00442
00443
00444 std::cerr << "The required video mode, " << resolution.first
00445 << "x" << resolution.second << "x" << DefaultBPP << " "
00446 << "is not supported\n";
00447
00448 if((video_flags&FULL_SCREEN) != 0) {
00449 std::cerr << "Try running the program with the --windowed option "
00450 << "using a " << DefaultBPP << "bpp X windows setting\n";
00451 }
00452
00453 if((video_flags&FULL_SCREEN) == 0) {
00454 std::cerr << "Try running with the --fullscreen option\n";
00455 }
00456
00457 return false;
00458 }
00459 }
00460
00461 if(force_bpp_ > 0) {
00462 bpp = force_bpp_;
00463 }
00464
00465 std::cerr << "setting mode to " << resolution.first << "x" << resolution.second << "x" << bpp << "\n";
00466 const int res = video_.setMode(resolution.first,resolution.second,bpp,video_flags);
00467 video_.setBpp(bpp);
00468 if(res == 0) {
00469 std::cerr << "required video mode, " << resolution.first << "x"
00470 << resolution.second << "x" << bpp << " is not supported\n";
00471 return false;
00472 }
00473
00474 return true;
00475 }
00476
00477 bool game_controller::init_config()
00478 {
00479
00480
00481 old_defines_map_.clear();
00482 reset_game_cfg();
00483 refresh_game_cfg();
00484
00485 game_config::load_config(game_config_.child("game_config"));
00486
00487 hotkey::load_hotkeys(game_config_);
00488 paths_manager_.set_paths(game_config_);
00489 ::init_textdomains(game_config_);
00490 about::set_about(game_config_);
00491
00492 return true;
00493 }
00494
00495 bool game_controller::init_language()
00496 {
00497 if(!::load_language_list())
00498 return false;
00499
00500 if (!::set_language(get_locale()))
00501 return false;
00502
00503 if(!no_gui_) {
00504 std::string wm_title_string = _("The Battle for Wesnoth");
00505 wm_title_string += " - " + game_config::revision;
00506 SDL_WM_SetCaption(wm_title_string.c_str(), NULL);
00507 }
00508
00509 hotkey::load_descriptions();
00510
00511 return true;
00512 }
00513
00514 bool game_controller::play_test()
00515 {
00516 static bool first_time = true;
00517
00518 if(test_mode_ == false) {
00519 return true;
00520 }
00521 if(!first_time)
00522 return false;
00523
00524 first_time = false;
00525
00526 state_.campaign_type = "test";
00527 state_.scenario = test_scenario_;
00528
00529 try {
00530 refresh_game_cfg();
00531 } catch(config::error&) {
00532 reset_game_cfg();
00533 refresh_game_cfg();
00534 return false;
00535 }
00536
00537 try {
00538 upload_log nolog(false);
00539 ::play_game(disp(),state_,game_config_,nolog);
00540 } catch(game::load_game_exception& e) {
00541 loaded_game_ = e.game;
00542 loaded_game_show_replay_ = e.show_replay;
00543 loaded_game_cancel_orders_ = e.cancel_orders;
00544 test_mode_ = false;
00545 return true;
00546 }
00547
00548 return false;
00549 }
00550
00551 bool game_controller::play_multiplayer_mode()
00552 {
00553 state_ = game_state();
00554
00555 if(!multiplayer_mode_) {
00556 return true;
00557 }
00558
00559 std::string era = "era_default";
00560 std::string scenario = "multiplayer_The_Freelands";
00561 std::map<int,std::string> side_types, side_controllers, side_algorithms;
00562 std::map<int,string_map> side_parameters;
00563 std::string turns = "50";
00564
00565 size_t sides_counted = 0;
00566
00567 for(++arg_; arg_ < argc_; ++arg_) {
00568 const std::string val(argv_[arg_]);
00569 if(val.empty()) {
00570 continue;
00571 }
00572
00573 std::vector<std::string> name_value = utils::split(val, '=');
00574 if(name_value.size() > 2) {
00575 std::cerr << "invalid argument '" << val << "'\n";
00576 return false;
00577 } else if(name_value.size() == 2) {
00578 const std::string name = name_value.front();
00579 const std::string value = name_value.back();
00580
00581 const std::string name_head = name.substr(0,name.size()-1);
00582 const char name_tail = name[name.size()-1];
00583 const bool last_digit = isdigit(name_tail) ? true:false;
00584 const size_t side = name_tail - '0';
00585
00586 if(last_digit && side > sides_counted) {
00587 std::cerr << "counted sides: " << side << "\n";
00588 sides_counted = side;
00589 }
00590
00591 if(name == "--scenario") {
00592 scenario = value;
00593 } else if(name == "--turns") {
00594 turns = value;
00595 } else if(name == "--era") {
00596 era = value;
00597 } else if(last_digit && name_head == "--controller") {
00598 side_controllers[side] = value;
00599 } else if(last_digit && name_head == "--algorithm") {
00600 side_algorithms[side] = value;
00601 } else if(last_digit && name_head == "--side") {
00602 side_types[side] = value;
00603 } else if(last_digit && name_head == "--parm") {
00604 const std::vector<std::string> name_value = utils::split(value, ':');
00605 if(name_value.size() != 2) {
00606 std::cerr << "argument to '" << name << "' must be in the format name:value\n";
00607 return false;
00608 }
00609
00610 side_parameters[side][name_value.front()] = name_value.back();
00611 } else {
00612 std::cerr << "unrecognized option: '" << name << "'\n";
00613 return false;
00614 }
00615 } else {
00616 if (val == "--exit-at-end") {
00617 game_config::exit_at_end = true;
00618 }
00619 }
00620 }
00621
00622 const config* const lvl = game_config_.find_child("multiplayer","id",scenario);
00623 if(lvl == NULL) {
00624 std::cerr << "Could not find scenario '" << scenario << "'\n";
00625 return false;
00626 }
00627
00628 state_.campaign_type = "multiplayer";
00629 state_.scenario = "";
00630 state_.snapshot = config();
00631
00632 config level = *lvl;
00633 std::vector<config*> story;
00634
00635 const config* const era_cfg = game_config_.find_child("era","id",era);
00636 if(era_cfg == NULL) {
00637 std::cerr << "Could not find era '" << era << "'\n";
00638 return false;
00639 }
00640
00641 level["turns"] = turns;
00642
00643 const config* const side = era_cfg->child("multiplayer_side");
00644 if(side == NULL) {
00645 std::cerr << "Could not find multiplayer side\n";
00646 return false;
00647 }
00648
00649 while(level.get_children("side").size() < sides_counted) {
00650 std::cerr << "now adding side...\n";
00651 level.add_child("side");
00652 }
00653
00654 int side_num = 1;
00655 for(config::child_itors itors = level.child_range("side"); itors.first != itors.second; ++itors.first, ++side_num) {
00656 std::map<int,std::string>::const_iterator type = side_types.find(side_num),
00657 controller = side_controllers.find(side_num),
00658 algorithm = side_algorithms.find(side_num);
00659
00660 const config* side = type == side_types.end() ?
00661 era_cfg->find_child("multiplayer_side", "random_faction", "yes") :
00662 era_cfg->find_child("multiplayer_side", "id", type->second);
00663
00664 if (side == NULL) {
00665 std::string side_name = (type == side_types.end() ? "default" : type->second);
00666 std::cerr << "Could not find side '" << side_name << "' for side " << side_num << "\n";
00667 return false;
00668 }
00669
00670 if (utils::string_bool((*side)["random_faction"])) {
00671 const config::child_list& factions = era_cfg->get_children("multiplayer_side");
00672 std::vector<std::string> faction_choices, faction_excepts;
00673 faction_choices = utils::split((*side)["choices"]);
00674 if(faction_choices.size() == 1 && faction_choices.front() == "") {
00675 faction_choices.clear();
00676 }
00677 faction_excepts = utils::split((*side)["except"]);;
00678 if(faction_excepts.size() == 1 && faction_excepts.front() == "") {
00679 faction_excepts.clear();
00680 }
00681 for(unsigned int i = 0, j = 0; i < factions.size(); ++i) {
00682 if (utils::string_bool((*factions[i])["random_faction"]) != true) {
00683 const std::string& faction_id = (*factions[i])["id"];
00684 if (
00685 !faction_choices.empty() &&
00686 std::find(faction_choices.begin(),faction_choices.end(),faction_id) == faction_choices.end()
00687 )
00688 continue;
00689 if (
00690 !faction_excepts.empty() &&
00691 std::find(faction_excepts.begin(),faction_excepts.end(),faction_id) != faction_excepts.end()
00692 )
00693 continue;
00694 j++;
00695 if (rand()%j == 0) {
00696 side = factions[i];
00697 }
00698 }
00699 }
00700 if (utils::string_bool((*side)["random_faction"], false) == true) {
00701 std::string side_name = (type == side_types.end() ? "default" : type->second);
00702 std::cerr << "Could not find any non-random faction for side " << side_num << "\n";
00703 return false;
00704 }
00705 }
00706
00707 char buf[20];
00708 snprintf(buf,sizeof(buf),"%d",side_num);
00709 (*itors.first)->values["side"] = buf;
00710
00711 (*itors.first)->values["canrecruit"] = "yes";
00712
00713 (*itors.first)->append(*side);
00714
00715 if(controller != side_controllers.end()) {
00716 (*itors.first)->values["controller"] = controller->second;
00717 }
00718
00719 if(algorithm != side_algorithms.end()) {
00720 (*itors.first)->values["ai_algorithm"] = algorithm->second;
00721 }
00722
00723 config& ai_params = (*itors.first)->add_child("ai");
00724
00725
00726 for(string_map::const_iterator j = side_parameters[side_num].begin(); j != side_parameters[side_num].end(); ++j) {
00727 (*itors.first)->values[j->first] = j->second;
00728 ai_params[j->first] = j->second;
00729 }
00730 }
00731
00732 try {
00733 upload_log nolog(false);
00734 state_.snapshot = level;
00735 ::play_game(disp(),state_,game_config_,nolog);
00736 } catch(game::error& e) {
00737 std::cerr << "caught error: '" << e.message << "'\n";
00738 } catch(game::load_game_exception& e) {
00739
00740 loaded_game_ = e.game;
00741 loaded_game_show_replay_ = e.show_replay;
00742 loaded_game_cancel_orders_ = e.cancel_orders;
00743 return true;
00744 } catch(twml_exception& e) {
00745 e.show(disp());
00746 return false;
00747 } catch(...) {
00748 std::cerr << "caught unknown error playing level...\n";
00749 }
00750
00751 return false;
00752 }
00753
00754 bool game_controller::is_loading() const
00755 {
00756 return loaded_game_.empty() == false;
00757 }
00758
00759 bool game_controller::load_game()
00760 {
00761 state_ = game_state();
00762
00763 bool show_replay = loaded_game_show_replay_;
00764 bool cancel_orders = loaded_game_cancel_orders_;
00765
00766 const std::string game = loaded_game_.empty() ? dialogs::load_game_dialog(disp(),game_config_,&show_replay,&cancel_orders) : loaded_game_;
00767
00768 loaded_game_ = "";
00769
00770 if(game == "") {
00771 return false;
00772 }
00773
00774 try {
00775
00776
00777
00778
00779 config cfg;
00780 std::string error_log;
00781 read_save_file(game,cfg,&error_log);
00782 if(!error_log.empty()) {
00783 gui::show_error_message(disp(),
00784 _("Warning: The file you have tried to load is corrupt. Loading anyway.\n") +
00785 error_log);
00786 }
00787
00788 reset_defines_map();
00789 defines_map_[cfg["difficulty"]] = preproc_define();
00790
00791 if(defines_map_.count("NORMAL")) {
00792 defines_map_["MEDIUM"] = preproc_define();
00793 }
00794
00795 const std::string& campaign_define = cfg["campaign_define"];
00796 if(campaign_define.empty() == false) {
00797 defines_map_[campaign_define] = preproc_define();
00798 }
00799 if (campaign_define.empty() && (cfg["campaign_type"] == "multiplayer")){
00800 defines_map_["MULTIPLAYER"] = preproc_define();
00801 }
00802
00803 const std::vector<std::string> campaign_xtra_defines = utils::split(cfg["campaign_extra_defines"]);
00804
00805 for(std::vector<std::string>::const_iterator i = campaign_xtra_defines.begin(); i != campaign_xtra_defines.end(); ++i) {
00806 defines_map_[*i] = preproc_define();
00807 }
00808
00809 try {
00810 refresh_game_cfg();
00811 } catch(config::error&) {
00812 reset_game_cfg();
00813 refresh_game_cfg();
00814 return false;
00815 }
00816
00817 const std::string version = cfg["version"];
00818 if(version != game_config::version) {
00819
00820
00821 if(version < game_config::min_savegame_version &&
00822 game_config::test_version.full != version &&
00823 game_config::test_version.full != game_config::version) {
00824
00825
00826 gui::message_dialog dlg(disp(), "", _("This save is from a version too old to be loaded."));
00827 dlg.show();
00828 return false;
00829 }
00830
00831 const int res = gui::dialog(disp(),"",
00832 _("This save is from a different version of the game. Do you want to try to load it?"),
00833 gui::YES_NO).show();
00834 if(res == 1) {
00835 return false;
00836 }
00837 }
00838
00839 state_ = game_state(cfg, show_replay);
00840
00841
00842
00843
00844
00845 const int seed = lexical_cast_default<int>
00846 (cfg["random_seed"], 42);
00847 const unsigned calls = show_replay ? 0 :
00848 lexical_cast_default<unsigned> (state_.snapshot["random_calls"]);
00849 state_.rng().seed_random(seed, calls);
00850
00851 } catch(game::error& e) {
00852 gui::show_error_message(disp(), _("The file you have tried to load is corrupt: '") + e.message + '\'');
00853 return false;
00854 } catch(config::error& e) {
00855 gui::show_error_message(disp(), _("The file you have tried to load is corrupt: '") + e.message + '\'');
00856 return false;
00857 } catch(io_exception&) {
00858 gui::show_error_message(disp(), _("File I/O Error while reading the game"));
00859 return false;
00860 } catch(twml_exception& e) {
00861 e.show(disp());
00862 return false;
00863 }
00864 recorder = replay(state_.replay_data);
00865 recorder.start_replay();
00866 recorder.set_skip(false);
00867
00868 LOG_CONFIG << "has snapshot: " << (state_.snapshot.child("side") ? "yes" : "no") << "\n";
00869
00870 if(state_.snapshot.child("side") == NULL) {
00871
00872 if (show_replay) {
00873
00874
00875 LOG_CONFIG << "replaying (start of scenario)\n";
00876 } else {
00877 LOG_CONFIG << "skipping...\n";
00878 recorder.set_skip(false);
00879 }
00880 } else {
00881
00882 if(show_replay) {
00883 statistics::clear_current_scenario();
00884 LOG_CONFIG << "replaying (snapshot)\n";
00885 } else {
00886 LOG_CONFIG << "setting replay to end...\n";
00887 recorder.set_to_end();
00888 if(!recorder.at_end()) {
00889 WRN_CONFIG << "recorder is not at the end!!!\n";
00890 }
00891 }
00892 }
00893
00894 if(state_.campaign_type == "tutorial") {
00895 defines_map_["TUTORIAL"] = preproc_define();
00896 } else if(state_.campaign_type == "multiplayer") {
00897 for(config::child_itors sides = state_.snapshot.child_range("side");
00898 sides.first != sides.second; ++sides.first) {
00899 if((**sides.first)["controller"] == "network")
00900 (**sides.first)["controller"] = "human";
00901 }
00902 }
00903
00904 if (cancel_orders) {
00905 for(config::child_itors sides = state_.snapshot.child_range("side");
00906 sides.first != sides.second; ++sides.first) {
00907 if((**sides.first)["controller"] == "human") {
00908 for (config::child_itors units = (**sides.first).child_range("unit");
00909 units.first != units.second; ++units.first) {
00910 (**units.first)["goto_x"] = "-999";
00911 (**units.first)["goto_y"] = "-999";
00912 }
00913 }
00914 }
00915 }
00916
00917 return true;
00918 }
00919
00920 void game_controller::set_tutorial()
00921 {
00922 state_ = game_state();
00923 state_.campaign_type = "tutorial";
00924 state_.scenario = "tutorial";
00925 state_.campaign_define = "TUTORIAL";
00926 reset_defines_map();
00927 defines_map_["TUTORIAL"] = preproc_define();
00928
00929 }
00930
00931 bool game_controller::new_campaign()
00932 {
00933 state_ = game_state();
00934 state_.campaign_type = "scenario";
00935
00936 config::child_list campaigns = game_config_.get_children("campaign");
00937 std::sort(campaigns.begin(),campaigns.end(),less_campaigns_rank);
00938
00939 std::vector<std::string> campaign_names;
00940 std::vector<std::pair<std::string,std::string> > campaign_desc;
00941
00942 for(config::child_list::const_iterator i = campaigns.begin(); i != campaigns.end(); ++i) {
00943 std::stringstream str;
00944 const std::string& icon = (**i)["icon"];
00945 const std::string desc = (**i)["description"];
00946 const std::string image = (**i)["image"];
00947 if(icon.empty()) {
00948 str << COLUMN_SEPARATOR;
00949 } else {
00950 str << IMAGE_PREFIX << icon << COLUMN_SEPARATOR;
00951 }
00952
00953 str << (**i)["name"];
00954
00955 campaign_names.push_back(str.str());
00956 campaign_desc.push_back(std::pair<std::string,std::string>(desc,image));
00957 }
00958
00959 if(campaign_names.size() <= 0) {
00960 gui::show_error_message(disp(),
00961 _("No campaigns are available.\n"));
00962 return false;
00963 }
00964 dialogs::campaign_preview_pane campaign_preview(disp().video(),&campaign_desc);
00965 gui::dialog cmenu(disp(), _("Play a campaign"), " ", gui::OK_CANCEL);
00966 cmenu.set_menu(campaign_names);
00967 cmenu.add_pane(&campaign_preview);
00968 gui::dialog::dimension_measurements dim = cmenu.layout();
00969 Uint16 screen_width = screen_area().w;
00970 Uint16 dialog_width = cmenu.get_frame().get_layout().exterior.w;
00971 if(screen_width < 850 && screen_width - dialog_width > 20) {
00972
00973 campaign_preview.set_width(campaign_preview.width() + screen_width - dialog_width - 20);
00974 dim = cmenu.layout();
00975 }
00976 SDL_Rect& preview_loc = dim.panes[&campaign_preview];
00977 preview_loc.y = dim.menu_y;
00978 if(dim.menu_height > 0) {
00979 preview_loc.h = dim.menu_height;
00980 } else {
00981 preview_loc.h = cmenu.get_menu().height();
00982 }
00983 cmenu.set_layout(dim);
00984
00985 if(cmenu.show() == -1) {
00986 return false;
00987 }
00988
00989 const config& campaign = *campaigns[cmenu.result()];
00990
00991 state_.campaign = campaign["id"];
00992 state_.abbrev = campaign["abbrev"];
00993 state_.scenario = campaign["first_scenario"];
00994
00995 const std::string difficulty_descriptions = campaign["difficulty_descriptions"];
00996 std::vector<std::string> difficulty_options = utils::split(difficulty_descriptions, ';');
00997
00998 const std::vector<std::string> difficulties = utils::split(campaign["difficulties"]);
00999
01000 if(difficulties.empty() == false) {
01001 if(difficulty_options.size() != difficulties.size()) {
01002 difficulty_options.resize(difficulties.size());
01003 std::copy(difficulties.begin(),difficulties.end(),difficulty_options.begin());
01004 }
01005
01006 gui::dialog dlg(disp(), _("Difficulty"),
01007 _("Select difficulty level:"), gui::OK_CANCEL);
01008 dlg.set_menu(difficulty_options);
01009 if(dlg.show() == -1) {
01010 return false;
01011 }
01012
01013 state_.difficulty = difficulties[dlg.result()];
01014 reset_defines_map();
01015 defines_map_[difficulties[dlg.result()]] = preproc_define();
01016 }
01017
01018 state_.campaign_define = campaign["define"];
01019 state_.campaign_xtra_defines = utils::split(campaign["extra_defines"]);
01020
01021 return true;
01022 }
01023
01024 }
01025
01026 bool game_controller::goto_campaign()
01027 {
01028 if(jump_to_campaign_){
01029 jump_to_campaign_ = false;
01030 if(new_campaign()) {
01031 play_game(game_controller::RELOAD_DATA);
01032 }else{
01033 return false;
01034 }
01035 }
01036 return true;
01037 }
01038
01039 bool game_controller::goto_multiplayer()
01040 {
01041 if(jump_to_multiplayer_){
01042 jump_to_multiplayer_ = false;
01043 if(play_multiplayer()){
01044 ;
01045 }else{
01046 return false;
01047 }
01048 }
01049 return true;
01050 }
01051
01052 static std::string format_file_size(const std::string& size_str)
01053 {
01054 double size = lexical_cast_default<double>(size_str,0.0);
01055
01056 const double k = 1024;
01057 if(size > 0.0) {
01058 std::string size_postfix = _("B");
01059 if(size > k) {
01060 size /= k;
01061 size_postfix = _("KB");
01062 if(size > k) {
01063 size /= k;
01064 size_postfix = _("MB");
01065 }
01066 }
01067
01068 std::ostringstream stream;
01069 #ifdef _MSC_VER
01070
01071
01072 stream.precision(1);
01073 stream << std::fixed << size << size_postfix;
01074 #else
01075 if (size < 100) stream.precision(3);
01076 else size = static_cast<int>(size);
01077 stream << size << size_postfix;
01078 #endif
01079 return stream.str();
01080 } else {
01081 return "";
01082 }
01083 }
01084
01085 namespace
01086 {
01087 void game_controller::reload_changed_game_config()
01088 {
01089
01090 old_defines_map_.clear();
01091 reset_game_cfg();
01092 data_tree_checksum(true);
01093 refresh_game_cfg();
01094 ::init_textdomains(game_config_);
01095 paths_manager_.set_paths(game_config_);
01096 clear_binary_paths_cache();
01097 }
01098
01099
01100 void game_controller::manage_addons()
01101 {
01102 int res;
01103 std::string host;
01104 if(new_widgets) {
01105 gui2::taddon_connect addon_dlg;
01106
01107 addon_dlg.set_host_name(preferences::campaign_server());
01108 addon_dlg.show(disp().video());
01109
01110 res = addon_dlg.get_retval();
01111 if(res == gui2::tbutton::OK) {
01112 res = 0;
01113 host = addon_dlg.host_name();
01114 }
01115 } else {
01116
01117 gui::dialog d(disp(),
01118 _("Connect to Server"),
01119 _("You will now connect to a server to download add-ons."),
01120 gui::OK_CANCEL);
01121 d.set_textbox(_("Server: "), preferences::campaign_server());
01122 d.add_button( new gui::dialog_button(disp().video(), _("Remove Add-ons"),
01123 gui::button::TYPE_PRESS, 2), gui::dialog::BUTTON_EXTRA);
01124 res = d.show();
01125 host = d.textbox_text();
01126 }
01127
01128 if (res == 0 )
01129 {
01130 download_campaigns(host);
01131 }
01132 else if (res == 2)
01133 {
01134
01135 std::vector<std::string> addons;
01136 std::vector<std::string> addon_dirs;
01137
01138 const std::string campaign_dir = get_user_data_dir() + "/data/campaigns/";
01139
01140 get_files_in_dir(campaign_dir, &addons, &addon_dirs, FILE_NAME_ONLY);
01141
01142
01143 std::vector<std::string>::iterator i = addons.begin();
01144 while(i != addons.end())
01145 {
01146 std::string::size_type pos = i->rfind(".cfg", i->size());
01147 if(pos == std::string::npos) {
01148 i = addons.erase(i);
01149 } else {
01150 i->erase(pos);
01151
01152 for(std::vector<std::string>::iterator j = addon_dirs.begin(); j != addon_dirs.end() ; ++j) {
01153 if (*i == *j) {
01154 addon_dirs.erase(j);
01155 break;
01156 }
01157 };
01158 std::replace(i->begin(), i->end(), '_', ' ');
01159 i++;
01160 }
01161 }
01162
01163 i = addon_dirs.begin();
01164 while(i != addon_dirs.end())
01165 {
01166 if (file_exists(campaign_dir + *i + "/_main.cfg")) {
01167 std::replace(i->begin(), i->end(), '_', ' ');
01168 addons.push_back(*i);
01169 i++;
01170 } else {
01171 i = addon_dirs.erase(i);
01172 }
01173 }
01174
01175 if (addons.empty())
01176 {
01177 gui::show_error_message(disp(), _("You have no Add-ons installed."));
01178 return;
01179 }
01180
01181 gui::menu::basic_sorter sorter;
01182 sorter.set_alpha_sort(1);
01183
01184
01185 int index = 0;
01186
01187 do
01188 {
01189 gui::dialog addon_dialog(disp(),
01190 _("Remove Add-ons"), _("Choose the add-on to remove."),
01191 gui::OK_CANCEL);
01192 gui::menu::imgsel_style &addon_style = gui::menu::bluebg_style;
01193
01194 gui::menu *addon_menu = new gui::menu(disp().video(), addons, false, -1,
01195 gui::dialog::max_menu_width, &sorter, &addon_style, false);
01196 addon_dialog.set_menu(addon_menu);
01197 index = addon_dialog.show();
01198
01199 if(index < 0) return;
01200
01201 std::string confirm_message = _("Are you sure you want to remove the add-on '$addon|'?");
01202 utils::string_map symbols;
01203 symbols["addon"] = addons.at(index);
01204 confirm_message = utils::interpolate_variables_into_string(confirm_message, &symbols);
01205 res = gui::dialog(disp(), _("Confirm"), confirm_message, gui::YES_NO).show();
01206 } while (res != 0);
01207
01208 bool delete_success = true;
01209
01210
01211 std::string filename = addons.at(index);
01212 std::replace(filename.begin(), filename.end(), ' ', '_');
01213 delete_success &= delete_directory(campaign_dir + filename);
01214
01215 if (delete_success)
01216 {
01217 delete_success &= delete_directory(campaign_dir + filename + ".cfg");
01218 reload_changed_game_config();
01219
01220 std::string message = _("Add-on '$addon|' deleted.");
01221 utils::string_map symbols;
01222 symbols["addon"] = addons.at(index);
01223 message = utils::interpolate_variables_into_string(message, &symbols);
01224
01225 gui::dialog dlg(disp(), _("Add-on deleted"), message, gui::OK_ONLY);
01226 dlg.show();
01227 }
01228 else
01229 {
01230
01231 gui::dialog dlg2(disp(), _("Error"), _("Add-on could not be deleted -- a file was not found."),
01232 gui::OK_ONLY);
01233 dlg2.show();
01234 }
01235 }
01236 else
01237 return;
01238 }
01239
01240 void game_controller::download_campaigns(std::string host)
01241 {
01242 const std::vector<std::string> items = utils::split(host, ':');
01243 if(items.empty()) {
01244 return;
01245 }
01246
01247 host = items.front();
01248 preferences::set_campaign_server(host);
01249
01250 try {
01251 const network::manager net_manager;
01252 const network::connection sock = dialogs::network_connect_dialog(disp(), _("Connecting to Server..."),
01253 items.front(), lexical_cast_default<int>(items.back(),15003) );
01254 if(!sock) {
01255 gui::show_error_message(disp(), _("Could not connect to host."));
01256 preferences::set_campaign_server("");
01257 return;
01258 }
01259
01260 config cfg;
01261 cfg.add_child("request_campaign_list");
01262
01263 network::send_data(cfg, sock, false);
01264
01265 network::connection res = dialogs::network_receive_dialog(disp(),_("Asking for list of add-ons"),cfg,sock);
01266 if(!res) {
01267 return;
01268 }
01269
01270 const config* const error = cfg.child("error");
01271 if(error != NULL) {
01272 gui::show_error_message(disp(), (*error)["message"]);
01273 return;
01274 }
01275
01276 const config* const campaigns_cfg = cfg.child("campaigns");
01277 if(campaigns_cfg == NULL) {
01278 gui::show_error_message(disp(), _("Error communicating with the server."));
01279 return;
01280 }
01281
01282 std::vector<std::string> campaigns, versions, uploads, options;
01283
01284 std::string sep(1, COLUMN_SEPARATOR);
01285
01286 std::stringstream heading;
01287 heading << HEADING_PREFIX << sep << _("Name") << sep << _("Version") << sep
01288 << _("Author") << sep << _("Downloads") << sep << _("Size");
01289
01290 const config::child_list& cmps = campaigns_cfg->get_children("campaign");
01291 const std::vector<std::string>& publish_options = available_campaigns();
01292
01293 std::vector<std::string> delete_options;
01294
01295 std::vector<int> sizes;
01296
01297 for(config::child_list::const_iterator i = cmps.begin(); i != cmps.end(); ++i) {
01298 const std::string& name = (**i)["name"];
01299 campaigns.push_back(name);
01300 versions.push_back((**i)["version"]);
01301 uploads.push_back((**i)["uploads"]);
01302
01303 if(std::count(publish_options.begin(),publish_options.end(),name) != 0) {
01304 delete_options.push_back(name);
01305 }
01306
01307 std::string title = (**i)["title"];
01308 if(title == "") {
01309 title = name;
01310 std::replace(title.begin(),title.end(),'_',' ');
01311 }
01312
01313 std::string version = (**i)["version"],
01314 author = (**i)["author"];
01315
01316 utils::truncate_as_wstring(title, 20);
01317 utils::truncate_as_wstring(version, 12);
01318 utils::truncate_as_wstring(author, 16);
01319
01320
01321 sizes.push_back(-atoi((**i)["size"].c_str()));
01322
01323 std::string icon = (**i)["icon"];
01324 if(icon.find("units/") != std::string::npos
01325 && icon.find_first_of('~') == std::string::npos) {
01326
01327 icon.append("~RC(magenta>red)");
01328 }
01329 options.push_back(IMAGE_PREFIX + icon + COLUMN_SEPARATOR +
01330 title + COLUMN_SEPARATOR +
01331 version + COLUMN_SEPARATOR +
01332 author + COLUMN_SEPARATOR +
01333 (**i)["downloads"].str() + COLUMN_SEPARATOR +
01334 format_file_size((**i)["size"]));
01335 }
01336
01337 options.push_back(heading.str());
01338
01339 for(std::vector<std::string>::const_iterator j = publish_options.begin(); j != publish_options.end(); ++j) {
01340 options.push_back(sep + _("Publish add-on: ") + *j);
01341 }
01342
01343 for(std::vector<std::string>::const_iterator d = delete_options.begin(); d != delete_options.end(); ++d) {
01344 options.push_back(sep + _("Delete add-on: ") + *d);
01345 }
01346
01347 if(campaigns.empty() && publish_options.empty()) {
01348 gui::show_error_message(disp(), _("There are no add-ons available for download from this server."));
01349 return;
01350 }
01351
01352 gui::menu::basic_sorter sorter;
01353 sorter.set_alpha_sort(1).set_alpha_sort(2).set_alpha_sort(3).set_numeric_sort(4).set_position_sort(5,sizes);
01354
01355 gui::dialog addon_dialog(disp(), _("Get Add-ons"),
01356 _("Choose the add-on to download."),
01357 gui::OK_CANCEL);
01358 gui::menu::imgsel_style addon_style(gui::menu::bluebg_style);
01359
01360
01361 addon_style.scale_images(font::relative_size(72), font::relative_size(72));
01362 gui::menu *addon_menu = new gui::menu(disp().video(), options, false, -1,
01363 gui::dialog::max_menu_width, &sorter, &addon_style, false);
01364 addon_dialog.set_menu(addon_menu);
01365 const int index = addon_dialog.show();
01366 if(index < 0) {
01367 return;
01368 }
01369
01370 if(index >= int(campaigns.size() + publish_options.size())) {
01371 delete_campaign(delete_options[index - int(campaigns.size() + publish_options.size())],sock);
01372 return;
01373 }
01374
01375 if(index >= int(campaigns.size())) {
01376 upload_campaign(publish_options[index - int(campaigns.size())],sock);
01377 return;
01378 }
01379
01380
01381 const config *selected_campaign = campaigns_cfg->find_child("campaign", "name", campaigns[index]);
01382 std::vector<std::string> dependencies = utils::split((*selected_campaign)["dependencies"]);
01383 if (!dependencies.empty()) {
01384
01385
01386 const std::vector<std::string>& installed = installed_campaigns();
01387 std::vector<std::string>::iterator i;
01388 std::string missing = "";
01389 for (i = dependencies.begin(); i != dependencies.end(); i++) {
01390 if (std::find(installed.begin(), installed.end(), *i) == installed.end()) {
01391 missing += "\n" + *i;
01392 }
01393 }
01394
01395
01396
01397 if (!missing.empty()) {
01398 if (gui::dialog(disp(),
01399 _("Dependencies"),
01400 std::string(_("This add-on requires the following additional dependencies:")) +
01401 "\n" + missing +
01402 "\n" + _("Do you still want to download it?"), gui::OK_CANCEL).show())
01403 return;
01404 }
01405 }
01406
01407 config request;
01408 request.add_child("request_campaign")["name"] = campaigns[index];
01409
01410 network::send_data(request, sock, false);
01411
01412 res = dialogs::network_receive_dialog(disp(),_("Downloading add-on..."),cfg,sock);
01413 if(!res) {
01414 return;
01415 }
01416
01417 if(cfg.child("error") != NULL) {
01418 gui::show_error_message(disp(), (*cfg.child("error"))["message"]);
01419 return;
01420 }
01421
01422 if(!check_names_legal(cfg)) {
01423 gui::show_error_message(disp(), "The add-on has an invalid file or directory name and can not be installed.");
01424 return;
01425 }
01426
01427
01428
01429 remove_campaign(campaigns[index]);
01430
01431
01432 config *maindir = cfg.find_child("dir", "name", campaigns[index]);
01433 if (maindir) {
01434 config f;
01435 f["name"] = "info.cfg";
01436 std::string s;
01437 s += "[info]\n";
01438 s += "version=\"" + versions[index] + "\"\n";
01439 s += "uploads=\"" + uploads[index] + "\"\n";
01440 s += "[/info]\n";
01441 f["contents"] = s;
01442 maindir->add_child("file", f);
01443 }
01444
01445
01446 unarchive_campaign(cfg);
01447
01448 reload_changed_game_config();
01449
01450 std::string warning = "";
01451 std::vector<config *> scripts = find_scripts(cfg, ".unchecked");
01452 if (!scripts.empty()) {
01453 warning += "\nUnchecked script files found:";
01454 std::vector<config *>::iterator i;
01455 for (i = scripts.begin(); i != scripts.end(); ++i) {
01456 warning += "\n" + (**i)["name"];
01457 }
01458 }
01459
01460
01461 gui::message_dialog dlg(disp(),_("Add-on Installed"),_("The add-on has been installed."));
01462 dlg.show();
01463 } catch(config::error&) {
01464 gui::show_error_message(disp(), _("Network communication error."));
01465 } catch(network::error&) {
01466 gui::show_error_message(disp(), _("Remote host disconnected."));
01467 } catch(io_exception&) {
01468 gui::show_error_message(disp(), _("There was a problem creating the files necessary to install this add-on."));
01469 } catch(twml_exception& e) {
01470 e.show(disp());
01471 }
01472 }
01473
01474 void game_controller::upload_campaign(const std::string& campaign, network::connection sock)
01475 {
01476 config request_terms;
01477 request_terms.add_child("request_terms");
01478
01479 network::send_data(request_terms, sock, false);
01480 config data;
01481 sock = network::receive_data(data,sock,5000);
01482 if(!sock) {
01483 gui::show_error_message(disp(), _("Connection timed out"));
01484 return;
01485 } else if(data.child("error")) {
01486 std::string error_message = _("The server responded with an error: \"$error|\"");
01487 utils::string_map symbols;
01488 symbols["error"] = (*data.child("error"))["message"].str();
01489 error_message = utils::interpolate_variables_into_string(error_message, &symbols);
01490 gui::show_error_message(disp(), error_message);
01491 return;
01492 } else if(data.child("message")) {
01493 const int res = gui::dialog(disp(),_("Terms"),(*data.child("message"))["message"],gui::OK_CANCEL).show();
01494 if(res != 0) {
01495 return;
01496 }
01497 }
01498
01499 config cfg;
01500 get_campaign_info(campaign,cfg);
01501
01502 std::string passphrase = cfg["passphrase"];
01503 if(passphrase.empty()) {
01504 passphrase.resize(8);
01505 for(size_t n = 0; n != 8; ++n) {
01506 passphrase[n] = 'a' + (rand()%26);
01507 }
01508 cfg["passphrase"] = passphrase;
01509 set_campaign_info(campaign,cfg);
01510 }
01511
01512 cfg["name"] = campaign;
01513
01514 config campaign_data;
01515 archive_campaign(campaign,campaign_data);
01516
01517 data.clear();
01518 data.add_child("upload",cfg).add_child("data",campaign_data);
01519
01520 LOG_NET << "uploading campaign...\n";
01521
01522 network::send_data(data, sock, false);
01523
01524 sock = dialogs::network_send_dialog(disp(),_("Sending add-on"),data,sock);
01525 if(!sock) {
01526 return;
01527 } else if(data.child("error")) {
01528 gui::show_error_message(disp(), _("The server responded with an error: \"") +
01529 (*data.child("error"))["message"].str() + '"');
01530 } else if(data.child("message")) {
01531
01532 gui::message_dialog dlg(disp(),_("Response"),(*data.child("message"))["message"]);
01533 dlg.show();
01534 }
01535 }
01536
01537 void game_controller::delete_campaign(const std::string& campaign, network::connection sock)
01538 {
01539 config cfg;
01540 get_campaign_info(campaign,cfg);
01541
01542 config msg;
01543 msg["name"] = campaign;
01544 msg["passphrase"] = cfg["passphrase"];
01545
01546 config data;
01547 data.add_child("delete",msg);
01548
01549
01550 network::send_data(data, sock, false);
01551
01552 sock = network::receive_data(data,sock,5000);
01553 if(!sock) {
01554 gui::show_error_message(disp(), _("Connection timed out"));
01555 } else if(data.child("error")) {
01556 gui::show_error_message(disp(), _("The server responded with an error: \"") +
01557 (*data.child("error"))["message"].str() + '"');
01558 } else if(data.child("message")) {
01559
01560 gui::message_dialog dlg(disp(),_("Response"),(*data.child("message"))["message"]);
01561 dlg.show();
01562 }
01563 }
01564
01565 void game_controller::remove_campaign(const std::string& campaign)
01566 {
01567 const std::string campaign_dir = get_user_data_dir() + "/data/campaigns/" + campaign;
01568 delete_directory(campaign_dir);
01569 if (file_exists(campaign_dir + ".cfg"))
01570 delete_directory(campaign_dir + ".cfg");
01571 }
01572
01573
01574 bool game_controller::play_multiplayer()
01575 {
01576 int res;
01577
01578 state_ = game_state();
01579 state_.campaign_type = "multiplayer";
01580 state_.campaign_define = "MULTIPLAYER";
01581
01582
01583
01584
01585 if( multiplayer_server_.empty() ){
01586 if(new_widgets) {
01587 gui2::tmp_method_selection dlg;
01588
01589 dlg.show(disp().video());
01590
01591 if(dlg.get_retval() == gui2::tbutton::OK) {
01592 std::cerr << "OK\n";
01593 res = dlg.get_choice();
01594 } else {
01595 std::cerr << "CANCEL\n";
01596 return false;
01597
01598 }
01599
01600 } else {
01601
01602 std::vector<std::string> host_or_join;
01603 std::string const pre = IMAGE_PREFIX + std::string("icons/icon-");
01604 char const sep1 = COLUMN_SEPARATOR, sep2 = HELP_STRING_SEPARATOR;
01605
01606 host_or_join.push_back(pre + "server.png"
01607 + sep1 + _("Join Official Server")
01608 + sep2 + _("Log on to the official Wesnoth multiplayer server"));
01609 host_or_join.push_back(pre + "serverother.png"
01610 + sep1 + _("Connect to Server")
01611 + sep2 + _("Join a different server"));
01612 host_or_join.push_back(pre + "hotseat.png"
01613 + sep1 + _("Local Game")
01614 + sep2 + _("Play a multiplayer game with the AI or humans sharing the same machine"));
01615
01616 std::string login = preferences::login();
01617
01618 {
01619 gui::dialog d(disp(), _("Multiplayer"), "", gui::OK_CANCEL);
01620 d.set_menu(host_or_join);
01621 d.set_textbox(_("Login: "), login, mp::max_login_size, font::relative_size(250));
01622 res = d.show();
01623 login = d.textbox_text();
01624 }
01625 if (res < 0)
01626 return false;
01627
01628
01629 preferences::set_login(login);
01630 }
01631
01632 }else{
01633 res = 3;
01634 }
01635
01636 try {
01637
01638 {
01639 reset_defines_map();
01640 defines_map_[state_.campaign_define] = preproc_define();
01641 refresh_game_cfg();
01642 events::discard(INPUT_MASK);
01643 cursor::set(cursor::NORMAL);
01644 }
01645
01646 if(res == 2) {
01647 std::vector<std::string> chat;
01648 config game_data;
01649
01650 const mp::controller cntr = mp::CNTR_LOCAL;
01651 const bool is_server = false;
01652
01653 mp::start_server(disp(), game_config_, cntr, is_server);
01654
01655 } else if(res == 0 || res == 1 || res == 3 ) {
01656 std::string host;
01657 if(res == 0) {
01658 host = preferences::server_list().front().address;
01659 }else if(res == 3){
01660 host = multiplayer_server_;
01661 multiplayer_server_ = "";
01662 }
01663 mp::start_client(disp(), game_config_, host);
01664 }
01665 } catch(game::load_game_failed& e) {
01666 gui::show_error_message(disp(), _("The game could not be loaded: ") + e.message);
01667 } catch(game::game_error& e) {
01668 gui::show_error_message(disp(), _("Error while playing the game: ") + e.message);
01669 } catch(network::error& e) {
01670 if(e.message != "") {
01671 ERR_NET << "caught network::error: " << e.message << "\n";
01672
01673 gui::dialog dlg(disp(),"",e.message,gui::OK_ONLY);
01674 dlg.show();
01675 } else {
01676 ERR_NET << "caught network::error\n";
01677 }
01678 } catch(config::error& e) {
01679 if(e.message != "") {
01680 ERR_CONFIG << "caught config::error: " << e.message << "\n";
01681
01682 gui::dialog dlg2(disp(),"",e.message,gui::OK_ONLY);
01683 dlg2.show();
01684 } else {
01685 ERR_CONFIG << "caught config::error\n";
01686 }
01687 } catch(gamemap::incorrect_format_exception& e) {
01688 gui::show_error_message(disp(), std::string(_("The game map could not be loaded: ")) + e.msg_);
01689 } catch(game::load_game_exception& e) {
01690
01691 loaded_game_ = e.game;
01692 loaded_game_show_replay_ = e.show_replay;
01693 loaded_game_cancel_orders_ = e.cancel_orders;
01694 } catch(twml_exception& e) {
01695 e.show(disp());
01696 }
01697
01698 return false;
01699 }
01700
01701 bool game_controller::change_language()
01702 {
01703 if(new_widgets) {
01704 gui2::tlanguage_selection dlg;
01705
01706 dlg.show(disp().video());
01707
01708 if(dlg.get_retval() == gui2::tbutton::OK) {
01709 if(!no_gui_) {
01710 std::string wm_title_string = _("The Battle for Wesnoth");
01711 wm_title_string += " - " + game_config::revision;
01712 SDL_WM_SetCaption(wm_title_string.c_str(), NULL);
01713 }
01714
01715 refresh_game_cfg(true);
01716 }
01717
01718 } else {
01719 const std::vector<language_def>& languages = get_languages();
01720 std::vector<std::string> langs;
01721
01722 for (std::vector<language_def>::const_iterator itor = languages.begin();
01723 itor != languages.end(); ++itor) {
01724 if (*itor == get_language()) {
01725 langs.push_back("*" + itor->language);
01726 } else {
01727 langs.push_back(itor->language);
01728 }
01729 }
01730
01731 gui::dialog lmenu(disp(),_("Language"),
01732 _("Choose your preferred language:"),
01733 gui::OK_CANCEL);
01734 lmenu.set_menu(langs);
01735 const int res = lmenu.show();
01736 if(size_t(res) < langs.size()) {
01737 ::set_language(languages[res]);
01738 preferences::set_language(languages[res].localename);
01739
01740 if(!no_gui_) {
01741 std::string wm_title_string = _("The Battle for Wesnoth");
01742 wm_title_string += " - " + game_config::revision;
01743 SDL_WM_SetCaption(wm_title_string.c_str(), NULL);
01744 }
01745
01746 refresh_game_cfg(true);
01747 } else {
01748 return false;
01749 }
01750
01751 font::load_font_config();
01752 hotkey::load_descriptions();
01753 }
01754 return true;
01755 }
01756
01757 void game_controller::show_preferences()
01758 {
01759 const preferences::display_manager disp_manager(&disp());
01760 preferences::show_preferences_dialog(disp(),game_config_);
01761
01762 disp().redraw_everything();
01763 }
01764
01765 void game_controller::show_upload_begging()
01766 {
01767 upload_log_dialog::show_beg_dialog(disp());
01768
01769 disp().redraw_everything();
01770 }
01771
01772
01773 void game_controller::read_configs(std::string& error_log)
01774 {
01775 preproc_map defines_map(defines_map_);
01776
01777 std::string user_error_log;
01778
01779 scoped_istream stream = preprocess_file("data/", &defines_map, &error_log);
01780
01781
01782 if (loadscreen::global_loadscreen) {
01783 loadscreen::global_loadscreen->parser_counter = 0;
01784 }
01785
01786 read(game_config_, *stream, &error_log);
01787
01788
01789 const std::string user_campaign_dir = get_user_data_dir() + "/data/campaigns/";
01790 std::vector<std::string> user_campaigns, error_campaigns;
01791 get_files_in_dir(user_campaign_dir,NULL,&user_campaigns,ENTIRE_FILE_PATH);
01792 for(std::vector<std::string>::const_iterator uc = user_campaigns.begin(); uc != user_campaigns.end(); ++uc) {
01793 std::string oldstyle_cfg = *uc + ".cfg";
01794 std::string main_cfg = *uc + "/_main.cfg";
01795 std::string toplevel;
01796 if (file_exists(oldstyle_cfg))
01797 toplevel = oldstyle_cfg;
01798 else if (file_exists(main_cfg))
01799 toplevel = main_cfg;
01800 else
01801 continue;
01802
01803 try {
01804 preproc_map user_defines_map(defines_map);
01805 scoped_istream stream = preprocess_file(toplevel, &user_defines_map);
01806
01807 std::string campaign_error_log;
01808
01809 config user_campaign_cfg;
01810 read(user_campaign_cfg,*stream,&campaign_error_log);
01811
01812 if(campaign_error_log.empty()) {
01813 game_config_.append(user_campaign_cfg);
01814 } else {
01815 user_error_log += campaign_error_log;
01816 error_campaigns.push_back(*uc);
01817 }
01818 } catch(config::error& err) {
01819 ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
01820 error_campaigns.push_back(*uc);
01821
01822 user_error_log += err.message + "\n";
01823 } catch(preproc_config::error&) {
01824 ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
01825 error_campaigns.push_back(*uc);
01826
01827
01828 } catch(io_exception&) {
01829 ERR_CONFIG << "error reading usermade add-on '" << *uc << "'\n";
01830 error_campaigns.push_back(*uc);
01831 }
01832 }
01833
01834 if(error_campaigns.empty() == false) {
01835 std::stringstream msg;
01836 msg << _n("The following add-on had errors and could not be loaded:",
01837 "The following add-ons had errors and could not be loaded:",
01838 error_campaigns.size());
01839 for(std::vector<std::string>::const_iterator i = error_campaigns.begin(); i != error_campaigns.end(); ++i) {
01840 msg << "\n" << *i;
01841 }
01842
01843 msg << "\n" << _("ERROR DETAILS:") << "\n" << font::nullify_markup(user_error_log);
01844
01845 gui::show_error_message(disp(),msg.str());
01846 }
01847
01848 game_config_.merge_children("units");
01849
01850 config& hashes = game_config_.add_child("multiplayer_hashes");
01851 for(config::child_list::const_iterator ch = game_config_.get_children("multiplayer").begin(); ch != game_config_.get_children("multiplayer").end(); ++ch) {
01852 hashes[(**ch)["id"]] = (*ch)->hash();
01853 }
01854
01855 }
01856
01857
01858 void game_controller::read_game_cfg(bool use_cache)
01859 {
01860 log_scope("read_game_cfg");
01861
01862 loadscreen::global_loadscreen_manager loadscreen_manager(disp().video());
01863
01864 bool is_valid = true;
01865 std::stringstream str;
01866 for(preproc_map::const_iterator i = defines_map_.begin(); i != defines_map_.end(); ++i) {
01867 if(i->second.value != "" || i->second.arguments.empty() == false) {
01868 is_valid = false;
01869 break;
01870 }
01871
01872 str << " " << i->first;
01873 }
01874
01875
01876
01877 if(is_valid) {
01878 const std::string& cache = get_cache_dir();
01879 if(cache != "") {
01880 sha1_hash sha(str.str());
01881 const std::string fname = cache + "/cache-v" + game_config::version + "-" + sha.display();
01882 const std::string fname_checksum = fname + ".checksum";
01883
01884 file_tree_checksum dir_checksum;
01885
01886 if(use_cache && !force_valid_cache_) {
01887 try {
01888 if(file_exists(fname_checksum)) {
01889 config checksum_cfg;
01890 scoped_istream stream = istream_file(fname_checksum);
01891 read(checksum_cfg, *stream);
01892 dir_checksum = file_tree_checksum(checksum_cfg);
01893 }
01894 } catch(config::error&) {
01895 ERR_CONFIG << "cache checksum is corrupt\n";
01896 } catch(io_exception&) {
01897 ERR_CONFIG << "error reading cache checksum\n";
01898 }
01899 }
01900
01901 if(force_valid_cache_) {
01902 LOG_CONFIG << "skipping cache validation (forced)\n";
01903 }
01904
01905 if(use_cache && file_exists(fname) && (force_valid_cache_ || (dir_checksum == data_tree_checksum()))) {
01906 LOG_CONFIG << "found valid cache at '" << fname << "' using it\n";
01907 log_scope("read cache");
01908 try {
01909 scoped_istream stream = istream_file(fname);
01910 read_compressed(game_config_, *stream);
01911 set_unit_data();
01912 return;
01913 } catch(config::error&) {
01914 ERR_CONFIG << "cache is corrupt. Loading from files\n";
01915 } catch(io_exception&) {
01916 ERR_CONFIG << "error reading cache. Loading from files\n";
01917 }
01918 }
01919
01920 LOG_CONFIG << "no valid cache found. Writing cache to '" << fname << " with defines_map "<< str.str() << "'\n";
01921 DBG_CONFIG << ((use_cache && file_exists(fname)) ? "yes":"no ") << " " << dir_checksum.modified << "==" << data_tree_checksum().modified << " " << dir_checksum.nfiles << "==" << data_tree_checksum().nfiles << " " << dir_checksum.sum_size << "==" << data_tree_checksum().sum_size << "\n";
01922
01923 std::string error_log;
01924
01925 read_configs(error_log);
01926
01927 if(!error_log.empty()) {
01928 gui::show_error_message(disp(),
01929 _("Warning: Errors occurred while loading game configuration files: '") +
01930 font::nullify_markup(error_log));
01931
01932 } else {
01933 try {
01934 scoped_ostream cache = ostream_file(fname);
01935 write_compressed(*cache, game_config_);
01936 config checksum_cfg;
01937 data_tree_checksum().write(checksum_cfg);
01938 scoped_ostream checksum = ostream_file(fname_checksum);
01939 write(*checksum, checksum_cfg);
01940 } catch(io_exception&) {
01941 ERR_FS << "could not write to cache '" << fname << "'\n";
01942 }
01943 }
01944
01945 set_unit_data();
01946 return;
01947 }
01948 }
01949
01950 ERR_CONFIG << "caching cannot be done. Reading file\n";
01951
01952 std::string error_log;
01953
01954 read_configs(error_log);
01955 if(!error_log.empty()) {
01956 gui::show_error_message(disp(),
01957 _("Warning: Errors occurred while loading game configuration files: '") +
01958 font::nullify_markup(error_log));
01959
01960 }
01961 set_unit_data();
01962 }
01963
01964 void game_controller::set_unit_data(){
01965 const config* const units = game_config_.child("units");
01966 if(units != NULL) {
01967 unit_type_data::types().set_config(*units);
01968 }
01969 }
01970
01971 void game_controller::refresh_game_cfg(bool reset_translations)
01972 {
01973 try {
01974 if(old_defines_map_.empty() || defines_map_ != old_defines_map_ || reset_translations) {
01975 cursor::setter cur(cursor::WAIT);
01976
01977 if(!reset_translations) {
01978 game_config_.clear();
01979 read_game_cfg(use_caching_);
01980 } else {
01981 game_config_.reset_translation();
01982
01983
01984 game_config::load_config(game_config_.child("game_config"));
01985 }
01986
01987 old_defines_map_ = defines_map_;
01988 }
01989 } catch(config::error& e) {
01990 ERR_CONFIG << "Error loading game configuration files\n";
01991 gui::show_error_message(disp(), _("Error loading game configuration files: '") +
01992 font::nullify_markup(e.message) + _("' (The game will now exit)"));
01993 throw e;
01994 } catch(preproc_config::error& e) {
01995 ERR_CONFIG << "Error loading game configuration files\n";
01996 gui::show_error_message(disp(), _("Error loading game configuration files: '") +
01997 font::nullify_markup(e.message) + _("' (The game will now exit)"));
01998 throw e;
01999 }
02000 }
02001
02002 void game_controller::reset_game_cfg()
02003 {
02004 reset_defines_map();
02005
02006
02007 #if defined(__APPLE__)
02008 defines_map_["APPLE"] = preproc_define();
02009 #endif
02010
02011 if(multiplayer_mode_) {
02012 defines_map_["MULTIPLAYER"] = preproc_define();
02013 } else {
02014 defines_map_["NORMAL"] = preproc_define();
02015 defines_map_["MEDIUM"] = preproc_define();
02016 }
02017
02018
02019 }
02020
02021 void game_controller::reset_defines_map()
02022 {
02023 defines_map_.clear();
02024
02025
02026
02027 #ifdef USE_TINY_GUI
02028 defines_map_["TINY"] = preproc_define();
02029 #endif
02030
02031 #ifdef USE_SMALL_GUI
02032 defines_map_["SMALL_GUI"] = preproc_define();
02033 #endif
02034
02035 #ifdef HAVE_PYTHON
02036 defines_map_["PYTHON"] = preproc_define();
02037 #endif
02038 }
02039
02040 void game_controller::play_game(RELOAD_GAME_DATA reload)
02041 {
02042 loadscreen::global_loadscreen_manager loadscreen_manager(disp().video());
02043 loadscreen::global_loadscreen->set_progress(0, _("Loading data files"));
02044 if(reload == RELOAD_DATA) {
02045 if(state_.campaign_define.empty() == false) {
02046 defines_map_[state_.campaign_define] = preproc_define();
02047 }
02048
02049 for( std::vector<std::string>::const_iterator i = state_.campaign_xtra_defines.begin();
02050 i != state_.campaign_xtra_defines.end(); ++i) {
02051 defines_map_[*i] = preproc_define();
02052 }
02053
02054 if(defines_map_.count("NORMAL")) {
02055 defines_map_["MEDIUM"] = preproc_define();
02056 }
02057
02058 try {
02059 refresh_game_cfg();
02060 } catch(config::error&) {
02061 reset_game_cfg();
02062 refresh_game_cfg();
02063 return;
02064 }
02065 }
02066
02067 loadscreen::global_loadscreen->set_progress(60);
02068
02069 const binary_paths_manager bin_paths_manager(game_config_);
02070
02071 try {
02072
02073 upload_log log(state_.campaign_type.empty()
02074 || state_.campaign_type == "scenario"
02075 || state_.campaign_type == "tutorial");
02076
02077 const LEVEL_RESULT result = ::play_game(disp(),state_,game_config_, log);
02078
02079
02080 if((result == VICTORY || result == LEVEL_CONTINUE_NO_SAVE) && (state_.campaign_type.empty() || state_.campaign_type != "multiplayer")) {
02081 the_end(disp());
02082 about::show_about(disp(),state_.campaign);
02083 }
02084 } catch(game::load_game_exception& e) {
02085
02086
02087 loaded_game_ = e.game;
02088 loaded_game_show_replay_ = e.show_replay;
02089 loaded_game_cancel_orders_ = e.cancel_orders;
02090
02091 } catch(twml_exception& e) {
02092 e.show(disp());
02093 }
02094 }
02095
02096 }
02097
02098 void game_controller::play_replay()
02099 {
02100 const binary_paths_manager bin_paths_manager(game_config_);
02101
02102 try {
02103 ::play_replay(disp(),state_,game_config_,video_);
02104
02105 } catch(game::load_game_exception& e) {
02106
02107
02108 loaded_game_ = e.game;
02109 loaded_game_show_replay_ = e.show_replay;
02110 loaded_game_cancel_orders_ = e.cancel_orders;
02111
02112 } catch(twml_exception& e) {
02113 e.show(disp());
02114 }
02115 }
02116
02117 game_controller::~game_controller()
02118 {
02119 delete gui::empty_menu;
02120 sound::close_sound();
02121 }
02122
02123
02124
02125
02126 static void safe_exit(int res) {
02127
02128 LOG_GENERAL << "exiting with code " << res << "\n";
02129 #ifdef OS2
02130 SDL_Quit();
02131 #endif
02132 exit(res);
02133 }
02134
02135
02136 static void gzip_codec(const std::string & input_file, const std::string & output_file, bool encode)
02137 {
02138 try {
02139 std::ofstream ofile(output_file.c_str(), std::ios_base::out
02140 | std::ios_base::binary | std::ios_base::binary);
02141 std::ifstream ifile(input_file.c_str(),
02142 std::ios_base::in | std::ios_base::binary);
02143 boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
02144 if(encode)
02145 in.push(boost::iostreams::gzip_compressor());
02146 else
02147 in.push(boost::iostreams::gzip_decompressor());
02148 in.push(ifile);
02149 boost::iostreams::copy(in, ofile);
02150 ifile.close();
02151 safe_exit(remove(input_file.c_str()));
02152 } catch(io_exception& e) {
02153 std::cerr << "IO error: " << e.what() << "\n";
02154 }
02155 }
02156
02157 static void gzip_encode(const std::string & input_file, const std::string & output_file)
02158 {
02159 gzip_codec(input_file, output_file, true);
02160 }
02161
02162 static void gzip_decode(const std::string & input_file, const std::string & output_file)
02163 {
02164 gzip_codec(input_file, output_file, false);
02165 }
02166
02167
02168
02169 static int play_game(int argc, char** argv)
02170 {
02171
02172 int arg;
02173 for(arg = 1; arg != argc; ++arg) {
02174 const std::string val(argv[arg]);
02175 if(val.empty()) {
02176 continue;
02177 }
02178
02179 if(val == "--help" || val == "-h") {
02180
02181 std::cout << "usage: " << argv[0]
02182 << " [OPTIONS] [DATA-DIRECTORY]\n"
02183 << " --bpp number sets BitsPerPixel value. Example: --bpp 32\n"
02184 << " --compress INFILE OUTFILE compresses a savefile (INFILE) that is in text WML\n"
02185 << " format into binary WML format (OUTFILE).\n"
02186 << " -d, --debug shows extra debugging information and enables\n"
02187 << " additional command mode options in-game.\n"
02188 << " --decompress INFILE OUTFILE decompresses a savefile (INFILE) that is in binary\n"
02189 << " WML format into text WML format (OUTFILE).\n"
02190 << " -f, --fullscreen runs the game in full screen mode.\n"
02191 << " --fps displays the number of frames per second the game\n"
02192 << " is currently running at, in a corner of the screen.\n"
02193 << " --gunzip INFILE.gz decompresses a file (INFILE.gz) in gzip format\n"
02194 << " and stores it without the .gz suffix.\n"
02195 << " INFILE.gz will be removed.\n"
02196 << " --gzip INFILE compresses a file (INFILE) in gzip format,\n"
02197 << " stores it as INFILE.gz and removes INFILE.\n"
02198 << " -h, --help prints this message and exits.\n"
02199 << " --load SAVEGAME loads the file SAVEGAME from the standard save\n"
02200 << " game directory.\n"
02201 << " --with-replay replays the file SAVEGAME loaded with --load option.\n"
02202 << " --log-<level>=<domain1>,<domain2>,...\n"
02203 << " sets the severity level of the log domains.\n"
02204 << " 'all' can be used to match any log domain.\n"
02205 << " Available levels: error, warning, info, debug.\n"
02206 << " By default the 'error' level is used.\n"
02207 << " --logdomains List defined log domains and exit.\n"
02208 << " --nocache disables caching of game data.\n"
02209 << " --validcache assume that cache is valid (dangerous)\n"
02210 << " --nosound runs the game without sounds and music.\n"
02211 << " --max-fps the maximum fps the game tries to run at the value\n"
02212 << " should be between the 1 and 1000, the default is 50.\n"
02213 << " --path prints the name of the game data directory and exits.\n"
02214 #ifdef HAVE_PYTHON
02215 << " --python-api prints the runtime documentation for the python API.\n"
02216 #endif
02217 << " -r, --resolution XxY sets the screen resolution. Example: -r 800x600\n"
02218 << " -t, --test runs the game in a small test scenario.\n"
02219 << " -v, --version prints the game's version number and exits.\n"
02220 << " -w, --windowed runs the game in windowed mode.\n"
02221 << " --no-delay run the game without any delays.\n"
02222 << " -c, --campaign skip menu, and go directly to campaign selection menu.\n"
02223 << " -s, --server [host] skip menu, and connect to the host if specified or to the first host in your preferences.\n"
02224 << " -m, --multiplayer runs a multiplayer game. There are additional\n"
02225 << " options that can be used as explained below:\n"
02226 << " --algorithm<number>=value selects a non-standard algorithm to be used by the\n"
02227 << " AI controller for this side.\n"
02228 << " --controller<number>=value selects the controller for this side.\n"
02229 << " --era=value selects the era to be played in by its id.\n"
02230 << " --nogui runs the game without the GUI. Must appear before\n"
02231 << " --multiplayer to have the desired effect.\n"
02232 << " --parm<number>=name:value sets additional parameters for this side.\n"
02233 << " --scenario=value selects a multiplayer scenario. The default\n"
02234 << " scenario is \"multiplayer_The_Freelands\".\n"
02235 << " --side<number>=value selects a faction of the current era for this side\n"
02236 << " by id.\n"
02237 << " --turns=value sets the number of turns. The default is \"50\".\n"
02238 << " --exit-at-end exit Wesnoth at end of scenario.\n"
02239 << " --new-widgets there is a new WIP widget toolkit this switch enables the new toolkit\n"
02240 << " (VERY EXPERIMENTAL don't file bug reports since most are known).\n"
02241 ;
02242 return 0;
02243 } else if(val == "--version" || val == "-v") {
02244 std::cout << _("Battle for Wesnoth") << " " << game_config::version
02245 << "\n";
02246 return 0;
02247 } else if(val == "--path") {
02248 std::cout << game_config::path
02249 << "\n";
02250 return 0;
02251 #ifdef HAVE_PYTHON
02252 } else if(val == "--python-api") {
02253 python_ai::invoke("documentation.py");
02254 return 0;
02255 #endif
02256 } else if (val.substr(0, 6) == "--log-") {
02257 size_t p = val.find('=');
02258 if (p == std::string::npos) {
02259 std::cerr << "unknown option: " << val << '\n';
02260 return 0;
02261 }
02262 std::string s = val.substr(6, p - 6);
02263 int severity;
02264 if (s == "error") severity = 0;
02265 else if (s == "warning") severity = 1;
02266 else if (s == "info") severity = 2;
02267 else if (s == "debug") severity = 3;
02268 else {
02269 std::cerr << "unknown debug level: " << s << '\n';
02270 return 0;
02271 }
02272 while (p != std::string::npos) {
02273 size_t q = val.find(',', p + 1);
02274 s = val.substr(p + 1, q == std::string::npos ? q : q - (p + 1));
02275 if (!lg::set_log_domain_severity(s, severity)) {
02276 std::cerr << "unknown debug domain: " << s << '\n';
02277 return 0;
02278 }
02279 p = q;
02280 }
02281
02282
02283
02284 } else if(val == "--compress" || val == "--decompress") {
02285 if(argc != arg+3) {
02286 std::cerr << "format of " << val << " command: " << val << " <input file> <output file>\n";
02287 return 0;
02288 }
02289
02290 const std::string input(argv[arg+1]);
02291 const std::string output(argv[arg+2]);
02292
02293 scoped_istream stream = istream_file(input);
02294 if (stream->fail()) {
02295 std::cerr << "could not read file '" << input << "'\n";
02296 return 0;
02297 }
02298
02299 config cfg;
02300
02301 const bool compress = val == "--compress";
02302 try {
02303 const bool is_compressed = detect_format_and_read(cfg, *stream);
02304 if(is_compressed && compress) {
02305 std::cerr << input << " is already compressed\n";
02306 return 0;
02307 } else if(!is_compressed && !compress) {
02308 std::cerr << input << " is already decompressed\n";
02309 return 0;
02310 }
02311
02312 scoped_ostream output_stream = ostream_file(output);
02313 write_possibly_compressed(*output_stream, cfg, compress);
02314 } catch(config::error& e) {
02315 std::cerr << input << " is not a valid Wesnoth file: " << e.message << "\n";
02316 } catch(io_exception& e) {
02317 std::cerr << "IO error: " << e.what() << "\n";
02318 }
02319
02320 return 0;
02321
02322 } else if(val == "--gzip") {
02323 if(argc != arg + 2) {
02324 std::cerr << "format of " << val << " command: " << val << " <input file>\n";
02325 return 2;
02326 }
02327
02328 const std::string input_file(argv[arg + 1]);
02329 const std::string output_file(input_file + ".gz");
02330 gzip_encode(input_file, output_file);
02331
02332 } else if(val == "--gunzip") {
02333 if(argc != arg + 2) {
02334 std::cerr << "format of " << val << " command: " << val << " <input file>\n";
02335 return 2;
02336 }
02337
02338 const std::string input_file(argv[arg + 1]);
02339 if(! is_gzip_file(input_file)) {
02340
02341 std::cerr << "file '" << input_file << "'isn't a .gz file\n";
02342 return 2;
02343 }
02344 const std::string output_file(
02345 input_file, 0, input_file.length() - 3);
02346
02347 gzip_decode(input_file, output_file);
02348
02349 } else if(val == "--logdomains") {
02350 std::cout << lg::list_logdomains() << "\n";
02351 return 0;
02352 }
02353
02354 }
02355
02356 srand(time(NULL));
02357
02358 game_controller game(argc,argv);
02359 const int start_ticks = SDL_GetTicks();
02360
02361
02362
02363
02364
02365
02366 std::setlocale(LC_ALL, "C");
02367 std::setlocale(LC_MESSAGES, "");
02368 const std::string& intl_dir = get_intl_dir();
02369 bindtextdomain (PACKAGE, intl_dir.c_str());
02370 bind_textdomain_codeset (PACKAGE, "UTF-8");
02371 bindtextdomain (PACKAGE "-lib", intl_dir.c_str());
02372 bind_textdomain_codeset (PACKAGE "-lib", "UTF-8");
02373 textdomain (PACKAGE);
02374
02375 bool res;
02376
02377
02378
02379
02380 res = font::load_font_config();
02381 if(res == false) {
02382 std::cerr << "could not initialize fonts\n";
02383 return 0;
02384 }
02385
02386 res = game.init_video();
02387 if(res == false) {
02388 std::cerr << "could not initialize display\n";
02389 return 0;
02390 }
02391
02392 const cursor::manager cursor_manager;
02393 cursor::set(cursor::WAIT);
02394
02395 loadscreen::global_loadscreen = new loadscreen(game.disp().video());
02396 loadscreen::global_loadscreen->clear_screen();
02397
02398 res = game.init_language();
02399 if(res == false) {
02400 std::cerr << "could not initialize the language\n";
02401 return 0;
02402 }
02403
02404 loadscreen::global_loadscreen->increment_progress(5, _("Loading game configuration."));
02405 res = game.init_config();
02406 if(res == false) {
02407 std::cerr << "could not initialize game config\n";
02408 return 0;
02409 }
02410 loadscreen::global_loadscreen->increment_progress(10, _("Re-initialize fonts for the current language."));
02411
02412 res = font::load_font_config();
02413 if(res == false) {
02414 std::cerr << "could not re-initialize fonts for the current language\n";
02415 return 0;
02416 }
02417
02418 #if defined(_X11) && !defined(__APPLE__)
02419 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
02420 #endif
02421
02422 config tips_of_day;
02423
02424 loadscreen::global_loadscreen->set_progress(100, _("Loading title screen."));
02425 delete loadscreen::global_loadscreen;
02426 loadscreen::global_loadscreen = NULL;
02427
02428 LOG_CONFIG << "time elapsed: "<< (SDL_GetTicks() - start_ticks) << " ms\n";
02429
02430 bool redraw_background = true;
02431
02432 for(int first_time = true;;first_time = false){
02433
02434
02435 if (!first_time){
02436
02437
02438 }
02439
02440
02441
02442 image::set_team_colors();
02443
02444 statistics::fresh_stats();
02445
02446 sound::play_music_repeatedly(game_config::title_music);
02447
02448 if(game.play_test() == false) {
02449 return 0;
02450 }
02451
02452 if(game.play_multiplayer_mode() == false) {
02453 return 0;
02454 }
02455
02456 recorder.clear();
02457
02458
02459 if(game.goto_campaign() == false){
02460 continue;
02461 }
02462
02463
02464
02465 if(game.goto_multiplayer() == false){
02466 continue;
02467 }
02468
02469 gui::TITLE_RESULT res = game.is_loading() ? gui::LOAD_GAME : gui::NOTHING;
02470
02471 while(res == gui::NOTHING) {
02472 res = gui::show_title(game.disp(),tips_of_day, redraw_background);
02473 if (res == gui::REDRAW_BACKGROUND) {
02474 redraw_background = true;
02475 res = gui::NOTHING;
02476 } else {
02477 redraw_background = false;
02478 }
02479 }
02480
02481 game_controller::RELOAD_GAME_DATA should_reload = game_controller::RELOAD_DATA;
02482
02483 if(res == gui::QUIT_GAME) {
02484 LOG_GENERAL << "quitting game...\n";
02485 return 0;
02486 } else if(res == gui::LOAD_GAME) {
02487 if(game.load_game() == false) {
02488 continue;
02489 }
02490
02491 should_reload = game_controller::NO_RELOAD_DATA;
02492 } else if(res == gui::TUTORIAL) {
02493 game.set_tutorial();
02494 } else if(res == gui::NEW_CAMPAIGN) {
02495 if(game.new_campaign() == false) {
02496 continue;
02497 }
02498 } else if(res == gui::MULTIPLAYER) {
02499 if(game.play_multiplayer() == false) {
02500
02501
02502
02503
02504 redraw_background = true;
02505 continue;
02506 }
02507 } else if(res == gui::CHANGE_LANGUAGE) {
02508 if(game.change_language() == true) {
02509 tips_of_day.clear();
02510 }
02511 continue;
02512 } else if(res == gui::EDIT_PREFERENCES) {
02513 game.show_preferences();
02514 if (game.disp().video().modeChanged()) {
02515 redraw_background = true;
02516 }
02517 continue;
02518 } else if(res == gui::SHOW_ABOUT) {
02519 about::show_about(game.disp());
02520 continue;
02521 } else if(res == gui::SHOW_HELP) {
02522 help::help_manager help_manager(&game.game_config(), NULL);
02523 help::show_help(game.disp());
02524 continue;
02525 } else if(res == gui::GET_ADDONS) {
02526 game.manage_addons();
02527 continue;
02528 } else if(res == gui::BEG_FOR_UPLOAD) {
02529 game.show_upload_begging();
02530 continue;
02531 #ifdef MAP_EDITOR
02532 } else if(res == gui::START_MAP_EDITOR) {
02533 gui::show_error_message(game.disp(), "The map editor is not available. Yet.");
02534
02535 continue;
02536 #endif
02537 }
02538
02539 if (recorder.at_end()){
02540 game.play_game(should_reload);
02541 }
02542 else{
02543 game.play_replay();
02544 }
02545
02546
02547 redraw_background = true;
02548 }
02549
02550 return 0;
02551 }
02552
02553 int main(int argc, char** argv)
02554 {
02555 #ifdef OS2
02556 if(SDL_Init(SDL_INIT_TIMER) < 0) {
02557 fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
02558 return(1);
02559 }
02560 #endif
02561
02562 try {
02563 std::cerr << "Battle for Wesnoth v" << game_config::revision << '\n';
02564 time_t t = time(NULL);
02565 std::cerr << "Started on " << ctime(&t) << "\n";
02566
02567 const int res = play_game(argc,argv);
02568 safe_exit(res);
02569 } catch(CVideo::error&) {
02570 std::cerr << "Could not initialize video. Exiting.\n";
02571 } catch(font::manager::error&) {
02572 std::cerr << "Could not initialize fonts. Exiting.\n";
02573 } catch(config::error& e) {
02574 std::cerr << e.message << "\n";
02575 } catch(gui::button::error&) {
02576 std::cerr << "Could not create button: Image could not be found\n";
02577 } catch(CVideo::quit&) {
02578
02579 } catch(end_level_exception&) {
02580 std::cerr << "caught end_level_exception (quitting)\n";
02581 } catch(std::bad_alloc&) {
02582 std::cerr << "Ran out of memory. Aborted.\n";
02583 } catch(twml_exception& e) {
02584 std::cerr << "WML exception:\nUser message: "
02585 << e.user_message << "\nDev message: " << e.dev_message << '\n';
02586 }
02587
02588 return 0;
02589 }
02590