/** * Adds an argument to the specified program options object. * @param arguments arguments collection to add argument to. * @param argument argument to add. * @param value value of argument.. */ template <class T> void add_argument(boost::program_options::variables_map& arguments, std::string argument, T value) { // add the argument to the collection arguments.insert( std::pair<std::string, boost::program_options::variable_value>( argument, boost::program_options::variable_value( boost::any(value), false ) ) ); }
int main(int argc, char** argv) #endif { #ifdef __APPLE__ // Correct working dir executable folder (not bundle folder) so we can use executable relative pathes std::string executablePath = argv[0]; std::string workDir = executablePath.substr(0, executablePath.rfind('/')); chdir(workDir.c_str()); // Check for updates OSX_checkForUpdates(); // Check that game data is prepared. Otherwise run vcmibuilder helper application FILE* check = fopen((VCMIDirs::get().localPath() + "/game_data_prepared").c_str(), "r"); if (check == nullptr) { system("open ./vcmibuilder.app"); return 0; } fclose(check); #endif std::cout << "Starting... " << std::endl; po::options_description opts("Allowed options"); opts.add_options() ("help,h", "display help and exit") ("version,v", "display version information and exit") ("battle,b", po::value<std::string>(), "runs game in duel mode (battle-only") ("start", po::value<std::string>(), "starts game from saved StartInfo file") ("onlyAI", "runs without human player, all players will be default AI") ("noGUI", "runs without GUI, implies --onlyAI") ("ai", po::value<std::vector<std::string>>(), "AI to be used for the player, can be specified several times for the consecutive players") ("oneGoodAI", "puts one default AI and the rest will be EmptyAI") ("autoSkip", "automatically skip turns in GUI") ("disable-video", "disable video player") ("nointro,i", "skips intro movies"); if(argc > 1) { try { po::store(po::parse_command_line(argc, argv, opts), vm); } catch(std::exception &e) { std::cerr << "Failure during parsing command-line options:\n" << e.what() << std::endl; } } po::notify(vm); if(vm.count("help")) { prog_help(opts); return 0; } if(vm.count("version")) { prog_version(); return 0; } if(vm.count("noGUI")) { gNoGUI = true; vm.insert(std::pair<std::string, po::variable_value>("onlyAI", po::variable_value())); } //Set environment vars to make window centered. Sometimes work, sometimes not. :/ putenv((char*)"SDL_VIDEO_WINDOW_POS"); putenv((char*)"SDL_VIDEO_CENTERED=1"); // Have effect on X11 system only (Linux). // For whatever reason in fullscreen mode SDL takes "raw" mouse input from DGA X11 extension // (DGA = Direct graphics access). Because this is raw input (before any speed\acceleration proceesing) // it may result in very small \ very fast mouse when game in fullscreen mode putenv((char*)"SDL_VIDEO_X11_DGAMOUSE=0"); // Init old logging system and new (temporary) logging system CStopWatch total, pomtime; std::cout.flags(std::ios::unitbuf); console = new CConsoleHandler; *console->cb = boost::bind(&processCommand, _1); console->start(); atexit(dispose); CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Client_log.txt", console); logConfig.configureDefault(); logGlobal->infoStream() <<"Creating console "<<pomtime.getDiff(); // Init filesystem and settings preinitDLL(::console); settings.init(); // Initialize logging based on settings logConfig.configure(); // Some basic data validation to produce better error messages in cases of incorrect install auto testFile = [](std::string filename, std::string message) -> bool { if (CResourceHandler::get()->existsResource(ResourceID(filename))) return true; logGlobal->errorStream() << "Error: " << message << " was not found!"; return false; }; if (!testFile("DATA/HELP.TXT", "Heroes III data") && !testFile("MODS/VCMI/MOD.JSON", "VCMI mod") && !testFile("DATA/StackQueueBgBig.PCX", "VCMI data")) exit(1); // These are unrecoverable errors // these two are optional + some installs have them on CD and not in data directory testFile("VIDEO/GOOD1A.SMK", "campaign movies"); testFile("SOUNDS/G1A.WAV", "campaign music"); //technically not a music but voiced intro sounds conf.init(); logGlobal->infoStream() <<"Loading settings: "<<pomtime.getDiff(); logGlobal->infoStream() << NAME; srand ( time(nullptr) ); const JsonNode& video = settings["video"]; const JsonNode& res = video["screenRes"]; //something is really wrong... if (res["width"].Float() < 100 || res["height"].Float() < 100) { logGlobal->errorStream() << "Fatal error: failed to load settings!"; logGlobal->errorStream() << "Possible reasons:"; logGlobal->errorStream() << "\tCorrupted local configuration file at " << VCMIDirs::get().userConfigPath() << "/settings.json"; logGlobal->errorStream() << "\tMissing or corrupted global configuration file at " << VCMIDirs::get().userConfigPath() << "/schemas/settings.json"; logGlobal->errorStream() << "VCMI will now exit..."; exit(EXIT_FAILURE); } if(!gNoGUI) { if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO)) { logGlobal->errorStream()<<"Something was wrong: "<< SDL_GetError(); exit(-1); } atexit(SDL_Quit); setScreenRes(res["width"].Float(), res["height"].Float(), video["bitsPerPixel"].Float(), video["fullscreen"].Bool()); logGlobal->infoStream() <<"\tInitializing screen: "<<pomtime.getDiff(); } CCS = new CClientState; CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler etc.) // Initialize video #if DISABLE_VIDEO CCS->videoh = new CEmptyVideoPlayer; #else if (!gNoGUI && !vm.count("disable-video")) CCS->videoh = new CVideoPlayer; else CCS->videoh = new CEmptyVideoPlayer; #endif logGlobal->infoStream()<<"\tInitializing video: "<<pomtime.getDiff(); //we can properly play intro only in the main thread, so we have to move loading to the separate thread boost::thread loading(init); if(!gNoGUI ) { if(!vm.count("battle") && !vm.count("nointro")) playIntro(); SDL_FillRect(screen,nullptr,0); } CSDL_Ext::update(screen); loading.join(); logGlobal->infoStream()<<"Initialization of VCMI (together): "<<total.getDiff(); if(!vm.count("battle")) { Settings session = settings.write["session"]; session["autoSkip"].Bool() = vm.count("autoSkip"); session["oneGoodAI"].Bool() = vm.count("oneGoodAI"); std::string fileToStartFrom; //none by default if(vm.count("start")) fileToStartFrom = vm["start"].as<std::string>(); if(fileToStartFrom.size() && boost::filesystem::exists(fileToStartFrom)) startGameFromFile(fileToStartFrom); //ommit pregame and start the game using settings from fiel else { if(fileToStartFrom.size()) { logGlobal->warnStream() << "Warning: cannot find given file to start from (" << fileToStartFrom << "). Falling back to main menu."; } GH.curInt = CGPreGame::create(); //will set CGP pointer to itself } } else { auto si = new StartInfo(); si->mode = StartInfo::DUEL; si->mapname = vm["battle"].as<std::string>(); si->playerInfos[PlayerColor(0)].color = PlayerColor(0); si->playerInfos[PlayerColor(1)].color = PlayerColor(1); startGame(si); } if(!gNoGUI) { mainGUIThread = new boost::thread(&CGuiHandler::run, &GH); listenForEvents(); } else { while(true) boost::this_thread::sleep(boost::posix_time::milliseconds(1000)); } return 0; }