00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "global.hpp"
00017
00018 #include "about.hpp"
00019 #include "addon/manager.hpp"
00020 #include "addon/manager_ui.hpp"
00021 #include "commandline_options.hpp"
00022 #include "game_controller.hpp"
00023 #include "game_controller_new.hpp"
00024 #include "gui/dialogs/title_screen.hpp"
00025 #ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
00026 #include "gui/widgets/debug.hpp"
00027 #endif
00028 #include "gui/widgets/window.hpp"
00029 #include "help.hpp"
00030 #include "loadscreen.hpp"
00031 #include "playcampaign.hpp"
00032 #include "preferences_display.hpp"
00033 #include "replay.hpp"
00034 #include "statistics.hpp"
00035 #include "serialization/parser.hpp"
00036 #include "serialization/validator.hpp"
00037 #include "version.hpp"
00038
00039 #include <cerrno>
00040 #include <clocale>
00041 #include <fstream>
00042 #include <libintl.h>
00043
00044 #include <boost/iostreams/copy.hpp>
00045 #include <boost/iostreams/filter/gzip.hpp>
00046
00047 #ifdef HAVE_VISUAL_LEAK_DETECTOR
00048 #include "vld.h"
00049 #endif
00050
00051
00052 #ifdef __amigaos4__
00053 const char __attribute__((used)) stackcookie[] = "\0$STACK: 16000000";
00054 #endif
00055
00056 static lg::log_domain log_config("config");
00057 #define LOG_CONFIG LOG_STREAM(info, log_config)
00058
00059 #define LOG_GENERAL LOG_STREAM(info, lg::general)
00060
00061 static lg::log_domain log_preprocessor("preprocessor");
00062 #define LOG_PREPROC LOG_STREAM(info,log_preprocessor)
00063
00064
00065
00066
00067 static void safe_exit(int res) {
00068
00069 LOG_GENERAL << "exiting with code " << res << "\n";
00070 #ifdef OS2
00071 SDL_Quit();
00072 #endif
00073 exit(res);
00074 }
00075
00076
00077 static void gzip_codec(const std::string & input_file, const std::string & output_file, bool encode)
00078 {
00079 try {
00080 std::ofstream ofile(output_file.c_str(), std::ios_base::out
00081 | std::ios_base::binary);
00082 std::ifstream ifile(input_file.c_str(),
00083 std::ios_base::in | std::ios_base::binary);
00084 boost::iostreams::filtering_streambuf<boost::iostreams::input> in;
00085 if(encode)
00086 in.push(boost::iostreams::gzip_compressor());
00087 else
00088 in.push(boost::iostreams::gzip_decompressor());
00089 in.push(ifile);
00090 boost::iostreams::copy(in, ofile);
00091 ifile.close();
00092 safe_exit(remove(input_file.c_str()));
00093 } catch(io_exception& e) {
00094 std::cerr << "IO error: " << e.what() << "\n";
00095 }
00096 }
00097
00098 static void gzip_encode(const std::string & input_file, const std::string & output_file)
00099 {
00100 gzip_codec(input_file, output_file, true);
00101 }
00102
00103 static void gzip_decode(const std::string & input_file, const std::string & output_file)
00104 {
00105 gzip_codec(input_file, output_file, false);
00106 }
00107
00108
00109 static int process_command_args(const commandline_options& cmdline_opts) {
00110
00111
00112
00113 if(cmdline_opts.config_dir) {
00114 set_preferences_dir(*cmdline_opts.config_dir);
00115 }
00116 if(cmdline_opts.config_path) {
00117 std::cout << get_user_data_dir() << '\n';
00118 return 0;
00119 }
00120 if(cmdline_opts.data_dir) {
00121 const std::string datadir = *cmdline_opts.data_dir;
00122 std::cerr << "Overriding data directory with " << datadir << std::endl;
00123 #ifdef _WIN32
00124
00125 if(datadir.c_str()[1] == ':') {
00126 #else
00127 if(datadir[0] == '/') {
00128 #endif
00129 game_config::path = datadir;
00130 } else {
00131 game_config::path = get_cwd() + '/' + datadir;
00132 }
00133
00134 if(!is_directory(game_config::path)) {
00135 std::cerr << "Could not find directory '" << game_config::path << "'\n";
00136 throw config::error("directory not found");
00137 }
00138
00139
00140 }
00141 if(cmdline_opts.gunzip) {
00142 const std::string input_file(*cmdline_opts.gunzip);
00143 if(!is_gzip_file(input_file)) {
00144 std::cerr << "file '" << input_file << "'isn't a .gz file\n";
00145 return 2;
00146 }
00147 const std::string output_file(
00148 input_file, 0, input_file.length() - 3);
00149 gzip_decode(input_file, output_file);
00150 }
00151 if(cmdline_opts.gzip) {
00152 const std::string input_file(*cmdline_opts.gzip);
00153 const std::string output_file(*cmdline_opts.gzip + ".gz");
00154 gzip_encode(input_file, output_file);
00155 }
00156 if(cmdline_opts.help) {
00157 std::cout << cmdline_opts;
00158 return 0;
00159 }
00160 if(cmdline_opts.log) {
00161 for(std::vector<boost::tuple<int, std::string> >::const_iterator it=cmdline_opts.log->begin(); it!=cmdline_opts.log->end(); ++it)
00162 {
00163 const std::string log_domain = it->get<1>();
00164 const int severity = it->get<0>();
00165 if (!lg::set_log_domain_severity(log_domain, severity))
00166 {
00167 std::cerr << "unknown log domain: " << log_domain << '\n';
00168 return 2;
00169 }
00170 }
00171 }
00172 if(cmdline_opts.logdomains) {
00173 std::cout << lg::list_logdomains(*cmdline_opts.logdomains);
00174 return 0;
00175 }
00176 if(cmdline_opts.new_syntax) {
00177 game_config::new_syntax = true;
00178 }
00179 if(cmdline_opts.path) {
00180 std::cout << game_config::path << "\n";
00181 return 0;
00182 }
00183 if(cmdline_opts.rng_seed) {
00184 srand(*cmdline_opts.rng_seed);
00185 }
00186 if(cmdline_opts.screenshot) {
00187 static char opt[] = "SDL_VIDEODRIVER=dummy";
00188 SDL_putenv(opt);
00189 }
00190 if(cmdline_opts.strict_validation) {
00191 strict_validation_enabled = true;
00192 }
00193 if(cmdline_opts.version) {
00194 std::cout << "Battle for Wesnoth" << " " << game_config::version << "\n";
00195 return 0;
00196 }
00197
00198
00199
00200 if ( cmdline_opts.preprocess ) {
00201
00202 std::string output_macros_file;
00203 preproc_map input_macros;
00204
00205 if( cmdline_opts.preprocess_input_macros ) {
00206 std::string file = *cmdline_opts.preprocess_input_macros;
00207 if ( file_exists( file ) == false )
00208 {
00209 std::cerr << "please specify an existing file. File "<< file <<" doesn't exist.\n";
00210 return 1;
00211 }
00212
00213 std::cerr << SDL_GetTicks() << " Reading cached defines from: " << file << "\n";
00214
00215 config cfg;
00216 scoped_istream stream = istream_file( file );
00217 read( cfg, *stream );
00218
00219 int read = 0;
00220
00221
00222 foreach ( const config::any_child &value, cfg.all_children_range() ) {
00223 const preproc_map::value_type def = preproc_define::read_pair( value.cfg );
00224 input_macros[def.first] = def.second;
00225 ++read;
00226 }
00227 std::cerr << SDL_GetTicks() << " Read " << read << " defines.\n";
00228 }
00229
00230 if( cmdline_opts.preprocess_output_macros ) {
00231
00232 if ( cmdline_opts.preprocess_output_macros->empty() == false )
00233 output_macros_file = *cmdline_opts.preprocess_output_macros;
00234 }
00235
00236 const std::string resourceToProcess(*cmdline_opts.preprocess_path);
00237 const std::string targetDir(*cmdline_opts.preprocess_target);
00238
00239 Uint32 startTime = SDL_GetTicks();
00240
00241 bool skipCore = false;
00242 bool skipTerrainGFX = false;
00243
00244 preproc_map defines_map( input_macros );
00245
00246 if ( cmdline_opts.preprocess_defines ) {
00247
00248
00249 foreach ( const std::string &define, *cmdline_opts.preprocess_defines ) {
00250 if (define.empty()){
00251 std::cerr << "empty define supplied\n";
00252 continue;
00253 }
00254
00255 LOG_PREPROC << "adding define: " << define << '\n';
00256 defines_map.insert(std::make_pair(define, preproc_define(define)));
00257
00258 if (define == "SKIP_CORE")
00259 {
00260 std::cerr << "'SKIP_CORE' defined.\n";
00261 skipCore = true;
00262 }
00263 else if (define == "NO_TERRAIN_GFX")
00264 {
00265 std::cerr << "'NO_TERRAIN_GFX' defined.\n";
00266 skipTerrainGFX = true;
00267 }
00268 }
00269 }
00270
00271
00272 defines_map["WESNOTH_VERSION"] = preproc_define(game_config::wesnoth_version.str());
00273
00274 std::cerr << "added " << defines_map.size() << " defines.\n";
00275
00276
00277 if (skipCore == false) {
00278 std::cerr << "preprocessing common macros from 'data/core' ...\n";
00279
00280
00281 preprocess_resource(game_config::path + "/data/core/macros",&defines_map);
00282 if (skipTerrainGFX == false)
00283 preprocess_resource(game_config::path + "/data/core/terrain-graphics",&defines_map);
00284
00285 std::cerr << "acquired " << (defines_map.size() - input_macros.size())
00286 << " 'data/core' defines.\n";
00287 }
00288 else
00289 std::cerr << "skipped 'data/core'\n";
00290
00291
00292 std::cerr << "preprocessing specified resource: "
00293 << resourceToProcess << " ...\n";
00294 preprocess_resource(resourceToProcess, &defines_map, true,true, targetDir);
00295 std::cerr << "acquired " << (defines_map.size() - input_macros.size())
00296 << " total defines.\n";
00297
00298 if ( output_macros_file.empty() == false )
00299 {
00300 std::string outputPath = targetDir + "/_MACROS_.cfg";
00301 if ( output_macros_file.empty() == false )
00302 outputPath = output_macros_file;
00303
00304 std::cerr << "writing '" << outputPath << "' with "
00305 << defines_map.size() << " defines.\n";
00306
00307 scoped_ostream out = ostream_file(outputPath);
00308 if (!out->fail())
00309 {
00310 config_writer writer(*out,false);
00311
00312 for(preproc_map::iterator itor = defines_map.begin();
00313 itor != defines_map.end(); ++itor)
00314 {
00315 (*itor).second.write(writer, (*itor).first);
00316 }
00317 }
00318 else
00319 std::cerr << "couldn't open the file.\n";
00320 }
00321
00322 std::cerr << "preprocessing finished. Took "<< SDL_GetTicks() - startTime << " ticks.\n";
00323 return 0;
00324 }
00325
00326
00327 return -1;
00328 }
00329
00330
00331
00332
00333
00334
00335
00336 static void init_locale() {
00337 #if defined _WIN32 || defined __APPLE__
00338 setlocale(LC_ALL, "English");
00339 #else
00340 std::setlocale(LC_ALL, "C");
00341 std::setlocale(LC_MESSAGES, "");
00342 #endif
00343 const std::string& intl_dir = get_intl_dir();
00344 bindtextdomain (PACKAGE, intl_dir.c_str());
00345 bind_textdomain_codeset (PACKAGE, "UTF-8");
00346 bindtextdomain (PACKAGE "-lib", intl_dir.c_str());
00347 bind_textdomain_codeset (PACKAGE "-lib", "UTF-8");
00348 textdomain (PACKAGE);
00349 }
00350
00351
00352
00353
00354
00355 static int do_gameloop(int argc, char** argv)
00356 {
00357 srand(time(NULL));
00358
00359 commandline_options cmdline_opts = commandline_options(argc,argv);
00360 game_config::wesnoth_program_dir = directory_name(argv[0]);
00361 int finished = process_command_args(cmdline_opts);
00362 if(finished != -1) {
00363 return finished;
00364 }
00365
00366
00367
00368 recorder.set_seed(rand());
00369 boost::shared_ptr<game_controller_abstract> game;
00370 if (game_config::new_syntax)
00371 game = boost::shared_ptr<game_controller_abstract>(new game_controller_new(cmdline_opts));
00372 else
00373 game = boost::shared_ptr<game_controller_abstract>(new game_controller(cmdline_opts,argv[0]));
00374 const int start_ticks = SDL_GetTicks();
00375
00376 init_locale();
00377
00378 bool res;
00379
00380
00381
00382
00383 res = font::load_font_config();
00384 if(res == false) {
00385 std::cerr << "could not initialize fonts\n";
00386 return 1;
00387 }
00388
00389 res = game->init_language();
00390 if(res == false) {
00391 std::cerr << "could not initialize the language\n";
00392 return 1;
00393 }
00394
00395 res = game->init_video();
00396 if(res == false) {
00397 std::cerr << "could not initialize display\n";
00398 return 1;
00399 }
00400
00401 if(preferences::joystick_support_enabled()) {
00402 res = game->init_joystick();
00403 if(res == false) {
00404 std::cerr << "could not initialize joystick\n";
00405 }
00406 }
00407
00408 const cursor::manager cursor_manager;
00409 cursor::set(cursor::WAIT);
00410
00411 loadscreen::global_loadscreen_manager loadscreen_manager(game->disp().video());
00412
00413 loadscreen::start_stage("init gui");
00414 gui2::init();
00415 const gui2::event::tmanager gui_event_manager;
00416
00417 loadscreen::start_stage("load config");
00418 res = game->init_config();
00419 if(res == false) {
00420 std::cerr << "could not initialize game config\n";
00421 return 1;
00422 }
00423 loadscreen::start_stage("init fonts");
00424
00425 res = font::load_font_config();
00426 if(res == false) {
00427 std::cerr << "could not re-initialize fonts for the current language\n";
00428 return 1;
00429 }
00430
00431 loadscreen::start_stage("refresh addons");
00432 refresh_addon_version_info_cache();
00433
00434 #if defined(_X11) && !defined(__APPLE__)
00435 SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
00436 #endif
00437
00438 config tips_of_day;
00439
00440 loadscreen::start_stage("titlescreen");
00441
00442 LOG_CONFIG << "time elapsed: "<< (SDL_GetTicks() - start_ticks) << " ms\n";
00443
00444 for (;;)
00445 {
00446
00447
00448 image::set_team_colors();
00449
00450 statistics::fresh_stats();
00451
00452 if (!game->is_loading()) {
00453 const config &cfg = game->game_config().child("titlescreen_music");
00454 if (cfg) {
00455 sound::play_music_repeatedly(game_config::title_music);
00456 foreach (const config &i, cfg.child_range("music")) {
00457 sound::play_music_config(i);
00458 }
00459 sound::commit_music_changes();
00460 } else {
00461 sound::empty_playlist();
00462 sound::stop_music();
00463 }
00464 }
00465
00466 loadscreen_manager.reset();
00467
00468 if(game->play_test() == false) {
00469 return 0;
00470 }
00471
00472 if(game->play_multiplayer_mode() == false) {
00473 return 0;
00474 }
00475
00476 if(game->play_screenshot_mode() == false) {
00477 return 0;
00478 }
00479
00480 recorder.clear();
00481
00482
00483 if(game->goto_campaign() == false){
00484 if (game->jump_to_campaign_id().empty())
00485 continue;
00486 else
00487 return 1;
00488 }
00489
00490
00491
00492 if(game->goto_multiplayer() == false){
00493 continue;
00494 }
00495
00496 if (game->goto_editor() == false) {
00497 return 0;
00498 }
00499
00500 gui2::ttitle_screen::tresult res = game->is_loading()
00501 ? gui2::ttitle_screen::LOAD_GAME
00502 : gui2::ttitle_screen::NOTHING;
00503
00504 const preferences::display_manager disp_manager(&game->disp());
00505
00506 const font::floating_label_context label_manager;
00507
00508 cursor::set(cursor::NORMAL);
00509 if(res == gui2::ttitle_screen::NOTHING) {
00510 const hotkey::basic_handler key_handler(&game->disp());
00511 gui2::ttitle_screen dlg;
00512 dlg.show(game->disp().video());
00513
00514 res = static_cast<gui2::ttitle_screen::tresult>(dlg.get_retval());
00515 }
00516
00517 game_controller_abstract::RELOAD_GAME_DATA should_reload = game_controller_abstract::RELOAD_DATA;
00518
00519 if(res == gui2::ttitle_screen::QUIT_GAME) {
00520 LOG_GENERAL << "quitting game...\n";
00521 return 0;
00522 } else if(res == gui2::ttitle_screen::LOAD_GAME) {
00523 if(game->load_game() == false) {
00524 game->clear_loaded_game();
00525 res = gui2::ttitle_screen::NOTHING;
00526 continue;
00527 }
00528 should_reload = game_controller_abstract::NO_RELOAD_DATA;
00529 } else if(res == gui2::ttitle_screen::TUTORIAL) {
00530 game->set_tutorial();
00531 } else if(res == gui2::ttitle_screen::NEW_CAMPAIGN) {
00532 if(game->new_campaign() == false) {
00533 continue;
00534 }
00535 } else if(res == gui2::ttitle_screen::MULTIPLAYER) {
00536 game_config::debug = game_config::mp_debug;
00537 if(game->play_multiplayer() == false) {
00538 continue;
00539 }
00540 } else if(res == gui2::ttitle_screen::CHANGE_LANGUAGE) {
00541 if (game->change_language()) {
00542 tips_of_day.clear();
00543 t_string::reset_translations();
00544 image::flush_cache();
00545 }
00546 continue;
00547 } else if(res == gui2::ttitle_screen::EDIT_PREFERENCES) {
00548 game->show_preferences();
00549 continue;
00550 } else if(res == gui2::ttitle_screen::SHOW_ABOUT) {
00551 about::show_about(game->disp());
00552 continue;
00553 } else if(res == gui2::ttitle_screen::SHOW_HELP) {
00554 help::help_manager help_manager(&game->game_config(), NULL);
00555 help::show_help(game->disp());
00556 continue;
00557 } else if(res == gui2::ttitle_screen::GET_ADDONS) {
00558
00559
00560 help::help_manager help_manager(&game->game_config(), NULL);
00561 if(manage_addons(game->disp())) {
00562 game->reload_changed_game_config();
00563 }
00564 continue;
00565 } else if(res == gui2::ttitle_screen::RELOAD_GAME_DATA) {
00566 loadscreen::global_loadscreen_manager loadscreen(game->disp().video());
00567 game->reload_changed_game_config();
00568 image::flush_cache();
00569 continue;
00570 } else if(res == gui2::ttitle_screen::START_MAP_EDITOR) {
00571
00572 if (game->start_editor() == editor::EXIT_QUIT_TO_DESKTOP) {
00573 return 0;
00574 }
00575 continue;
00576 }
00577
00578 if (recorder.at_end()){
00579 game->launch_game(should_reload);
00580 }
00581 else{
00582 game->play_replay();
00583 }
00584 }
00585 }
00586
00587
00588 #ifdef __native_client__
00589 int wesnoth_main(int argc, char** argv)
00590 #else
00591 int main(int argc, char** argv)
00592 #endif
00593 {
00594
00595 #ifdef HAVE_VISUAL_LEAK_DETECTOR
00596 VLDEnable();
00597 #endif
00598
00599 #if defined(_OPENMP) && !defined(_WIN32) && !defined(__APPLE__)
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 if (!getenv("OMP_WAIT_POLICY")) {
00613 setenv("OMP_WAIT_POLICY", "PASSIVE", 1);
00614 execv(argv[0], argv);
00615 }
00616 #endif
00617
00618 if(SDL_Init(SDL_INIT_TIMER) < 0) {
00619 fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
00620 return(1);
00621 }
00622
00623 try {
00624 std::cerr << "Battle for Wesnoth v" << game_config::revision << '\n';
00625 const time_t t = time(NULL);
00626 std::cerr << "Started on " << ctime(&t) << "\n";
00627
00628 const std::string exe_dir = get_exe_dir();
00629 if(!exe_dir.empty() && file_exists(exe_dir + "/data/_main.cfg")) {
00630 std::cerr << "Automatically found a possible data directory at "
00631 << exe_dir << '\n';
00632 game_config::path = exe_dir;
00633 }
00634
00635 const int res = do_gameloop(argc,argv);
00636 safe_exit(res);
00637 } catch(boost::program_options::error& e) {
00638 std::cerr << "Error in command line: " << e.what() << '\n';
00639 return 1;
00640 } catch(CVideo::error&) {
00641 std::cerr << "Could not initialize video. Exiting.\n";
00642 return 1;
00643 } catch(font::manager::error&) {
00644 std::cerr << "Could not initialize fonts. Exiting.\n";
00645 return 1;
00646 } catch(config::error& e) {
00647 std::cerr << e.message << "\n";
00648 return 1;
00649 } catch(gui::button::error&) {
00650 std::cerr << "Could not create button: Image could not be found\n";
00651 return 1;
00652 } catch(CVideo::quit&) {
00653
00654 } catch(end_level_exception&) {
00655 std::cerr << "caught end_level_exception (quitting)\n";
00656 } catch(twml_exception& e) {
00657 std::cerr << "WML exception:\nUser message: "
00658 << e.user_message << "\nDev message: " << e.dev_message << '\n';
00659 return 1;
00660 } catch(game_logic::formula_error& e) {
00661 std::cerr << e.what()
00662 << "\n\nGame will be aborted.\n";
00663 return 1;
00664 } catch(game::error &) {
00665
00666 return 1;
00667 } catch(std::bad_alloc&) {
00668 std::cerr << "Ran out of memory. Aborted.\n";
00669 return ENOMEM;
00670 }
00671
00672 return 0;
00673 }