LEVEL_RESULT playsingle_controller::play_scenario( const config::const_child_itors &story, bool skip_replay) { uint32_t start = SDL_GetTicks(); // level_ // save game: [snapshort] in save file // new game: [scenario] in <scenarios>.cfg // Start music. BOOST_FOREACH (const config &m, level_.child_range("music")) { sound::play_music_config(m); } sound::commit_music_changes(); if(!skip_replay) { // show_story(*gui_, level_["name"], story); // gui2::show_story(*gui_, level_["name"], story); } gui_->labels().read(level_); // Read sound sources assert(soundsources_manager_ != NULL); BOOST_FOREACH (const config &s, level_.child_range("sound_source")) { soundsource::sourcespec spec(s); soundsources_manager_->add(spec); } uint32_t end_sound_sources = SDL_GetTicks(); posix_print("playsingle_controller::play_scenario, sound sources, used time: %u ms\n", end_sound_sources - start); set_victory_when_enemy_no_city(level_["victory_when_enemy_no_city"].to_bool(true)); end_level_data &end_level = get_end_level_data(); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carryover_add"].to_bool(); try { uint32_t end_entering_try = SDL_GetTicks(); posix_print("playsingle_controller::play_scenario, entering try, used time: %u ms\n", end_entering_try - end_sound_sources); fire_prestart(!loading_game_); uint32_t end_fire_prestart = SDL_GetTicks(); posix_print("playsingle_controller::play_scenario, fire_prestrt, used time: %u ms\n", end_fire_prestart - end_entering_try); init_gui(); fire_start(!loading_game_); gui_->recalculate_minimap(); // replaying_ = (recorder.at_end() == false); // Initialize countdown clock. std::vector<team>::iterator t; for(t = teams_.begin(); t != teams_.end(); ++t) { if (gamestate_.mp_settings().mp_countdown && !loading_game_ ){ t->set_countdown_time(1000 * gamestate_.mp_settings().mp_countdown_init_time); } } // if we loaded a save file in linger mode, skip to it. if (linger_) { //determine the bonus gold handling for this scenario const config end_cfg = level_.child_or_empty("endlevel"); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carr`yover_add"].to_bool(); end_level.gold_bonus = end_cfg["bonus"].to_bool(true); end_level.carryover_report = false; throw end_level_exception(SKIP_TO_LINGER); } // Avoid autosaving after loading, but still // allow the first turn to have an autosave. bool save = !loading_game_; for(; ; first_player_ = 1) { play_turn(save); save = true; } //end for loop } catch(game::load_game_exception& lge) { // Loading a new game is effectively a quit. // if (lge.game != "") { gamestate_ = game_state(); } throw lge; } catch (end_level_exception &end_level_exn) { LEVEL_RESULT end_level_result = end_level_exn.result; if (!end_level.custom_endlevel_music.empty()) { if (end_level_result == DEFEAT) { set_defeat_music_list(end_level.custom_endlevel_music); } else { set_victory_music_list(end_level.custom_endlevel_music); } } if (teams_.empty()) { //store persistent teams gamestate_.snapshot = config(); return VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event } const bool obs = is_observer(); if (end_level_result == DEFEAT || end_level_result == VICTORY) { gamestate_.classification().completion = (end_level_exn.result == VICTORY) ? "victory" : "defeat"; // If we're a player, and the result is victory/defeat, then send // a message to notify the server of the reason for the game ending. if (!obs) { config cfg; config& info = cfg.add_child("info"); info["type"] = "termination"; info["condition"] = "game over"; info["result"] = gamestate_.classification().completion; network::send_data(cfg, 0); } else { gui2::show_transient_message(gui_->video(),_("Game Over"), _("The game is over.")); return OBSERVER_END; } } if (end_level_result == QUIT) { return QUIT; } else if (end_level_result == DEFEAT) { gamestate_.classification().completion = "defeat"; game_events::fire("defeat"); if (!obs) { const std::string& defeat_music = select_defeat_music(); if(defeat_music.empty() != true) sound::play_music_once(defeat_music); return DEFEAT; } else { return QUIT; } } else if (end_level_result == VICTORY) { gamestate_.classification().completion = !end_level.linger_mode ? "running" : "victory"; game_events::fire("victory"); // // Play victory music once all victory events // are finished, if we aren't observers. // // Some scenario authors may use 'continue' // result for something that is not story-wise // a victory, so let them use [music] tags // instead should they want special music. // if (!obs && end_level.linger_mode) { const std::string& victory_music = select_victory_music(); if(victory_music.empty() != true) sound::play_music_once(victory_music); } // Add all the units that survived the scenario. LOG_NG << "Add units that survived the scenario to the recall list.\n"; //store all units that survived (recall list for the next scenario) in snapshot gamestate_.snapshot = config(); //store gold and report victory store_gold(obs); return VICTORY; } else if (end_level_result == SKIP_TO_LINGER) { LOG_NG << "resuming from loaded linger state...\n"; //as carryover information is stored in the snapshot, we have to re-store it after loading a linger state gamestate_.snapshot = config(); store_gold(); return VICTORY; } } // end catch catch(network::error& e) { bool disconnect = false; if(e.socket) { e.disconnect(); disconnect = true; } config snapshot; to_config(snapshot); savegame::game_savegame save(heros_, heros_start_, gamestate_, *gui_, snapshot); save.save_game_interactive(gui_->video(), _("A network disconnection has occurred, and the game cannot continue. Do you want to save the game?"), gui::YES_NO); if(disconnect) { throw network::error(); } else { return QUIT; } } return QUIT; }
LEVEL_RESULT playsingle_controller::play_scenario( const config::const_child_itors &story, bool skip_replay) { LOG_NG << "in playsingle_controller::play_scenario()...\n"; // Start music. foreach (const config &m, level_.child_range("music")) { sound::play_music_config(m); } sound::commit_music_changes(); if(!skip_replay) { show_story(*gui_, level_["name"], story); } gui_->labels().read(level_); // Read sound sources assert(soundsources_manager_ != NULL); foreach (const config &s, level_.child_range("sound_source")) { soundsource::sourcespec spec(s); soundsources_manager_->add(spec); } set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true)); end_level_data &end_level = get_end_level_data(); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carryover_add"].to_bool(); bool past_prestart = false; LOG_NG << "entering try... " << (SDL_GetTicks() - ticks_) << "\n"; try { fire_prestart(!loading_game_); init_gui(); past_prestart = true; LOG_NG << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n"; events::raise_draw_event(); fire_start(!loading_game_); gui_->recalculate_minimap(); replaying_ = (recorder.at_end() == false); LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; // Initialize countdown clock. std::vector<team>::iterator t; for(t = teams_.begin(); t != teams_.end(); ++t) { if (gamestate_.mp_settings().mp_countdown && !loading_game_ ){ t->set_countdown_time(1000 * gamestate_.mp_settings().mp_countdown_init_time); } } // if we loaded a save file in linger mode, skip to it. if (linger_) { //determine the bonus gold handling for this scenario end_level.read(level_.child_or_empty("endlevel")); end_level.carryover_report = false; end_level.disabled = true; throw end_level_exception(SKIP_TO_LINGER); } // Avoid autosaving after loading, but still // allow the first turn to have an autosave. bool save = !loading_game_; ai_testing::log_game_start(); for(; ; first_player_ = 1) { play_turn(save); save = true; } //end for loop #ifdef _MSC_VER //MSVC claims that const game::load_game_exception& lge would be unreferenced... #pragma warning (push) #pragma warning (disable : 4101) #endif } catch(const game::load_game_exception& lge) { // Loading a new game is effectively a quit. // if (lge.game != "") { gamestate_ = game_state(); } throw; } catch (end_level_exception &end_level_exn) { if(!past_prestart) { draw_solid_tinted_rectangle( 0, 0, gui_->video().getx(), gui_->video().gety(), 0, 0, 0, 1.0, gui_->video().getSurface() ); update_rect(0, 0, gui_->video().getx(), gui_->video().gety()); } ai_testing::log_game_end(); LEVEL_RESULT end_level_result = end_level_exn.result; if (!end_level.custom_endlevel_music.empty()) { if (end_level_result == DEFEAT) { set_defeat_music_list(end_level.custom_endlevel_music); } else { set_victory_music_list(end_level.custom_endlevel_music); } } if (teams_.empty()) { //store persistent teams gamestate_.snapshot = config(); store_recalls(); return VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event } const bool obs = is_observer(); if (game_config::exit_at_end) { exit(0); } if (end_level_result == DEFEAT || end_level_result == VICTORY) { gamestate_.classification().completion = (end_level_exn.result == VICTORY) ? "victory" : "defeat"; // If we're a player, and the result is victory/defeat, then send // a message to notify the server of the reason for the game ending. if (!obs) { config cfg; config& info = cfg.add_child("info"); info["type"] = "termination"; info["condition"] = "game over"; info["result"] = gamestate_.classification().completion; network::send_data(cfg, 0); } else { gui2::show_transient_message(gui_->video(),_("Game Over"), _("The game is over.")); return OBSERVER_END; } } if (end_level_result == QUIT) { return QUIT; } else if (end_level_result == DEFEAT) { gamestate_.classification().completion = "defeat"; game_events::fire("defeat"); if (!obs) { const std::string& defeat_music = select_defeat_music(); if(defeat_music.empty() != true) sound::play_music_once(defeat_music); return DEFEAT; } else { return QUIT; } } else if (end_level_result == VICTORY) { gamestate_.classification().completion = !end_level.linger_mode ? "running" : "victory"; game_events::fire("victory"); // // Play victory music once all victory events // are finished, if we aren't observers. // // Some scenario authors may use 'continue' // result for something that is not story-wise // a victory, so let them use [music] tags // instead should they want special music. // if (!obs && end_level.linger_mode) { const std::string& victory_music = select_victory_music(); if(victory_music.empty() != true) sound::play_music_once(victory_music); } // Add all the units that survived the scenario. LOG_NG << "Add units that survived the scenario to the recall list.\n"; for(unit_map::iterator un = units_.begin(); un != units_.end(); ++un) { if (teams_[un->side() - 1].persistent()) { LOG_NG << "Added unit " << un->id() << ", " << un->name() << "\n"; un->new_turn(); un->new_scenario(); teams_[un->side() - 1].recall_list().push_back(*un); } } //store all units that survived (recall list for the next scenario) in snapshot gamestate_.snapshot = config(); store_recalls(); //store gold and report victory store_gold(obs); return VICTORY; } else if (end_level_result == SKIP_TO_LINGER) { LOG_NG << "resuming from loaded linger state...\n"; //as carryover information is stored in the snapshot, we have to re-store it after loading a linger state gamestate_.snapshot = config(); store_recalls(); store_gold(); return VICTORY; } } // end catch catch(network::error& e) { bool disconnect = false; if(e.socket) { e.disconnect(); disconnect = true; } savegame::game_savegame save(gamestate_, *gui_, to_config(), preferences::compress_saves()); save.save_game_interactive(gui_->video(), _("A network disconnection has occurred, and the game cannot continue. Do you want to save the game?"), gui::YES_NO); if(disconnect) { throw network::error(); } else { return QUIT; } } return QUIT; }