replay_controller.cpp

Go to the documentation of this file.
00001 /* $Id: replay_controller.cpp 25333 2008-03-30 13:49:03Z jhinrichs $ */
00002 /*
00003    Copyright (C) 2006 - 2008 by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
00004    wesnoth playlevel Copyright (C) 2003 by David White <dave@whitevine.net>
00005    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License version 2
00009    or at your option any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #include "global.hpp"
00017 
00018 #include "ai_interface.hpp"
00019 #include "config_adapter.hpp"
00020 #include "cursor.hpp"
00021 #include "filesystem.hpp"
00022 #include "game_preferences.hpp"
00023 #include "gettext.hpp"
00024 #include "game_events.hpp"
00025 #include "halo.hpp"
00026 #include "help.hpp"
00027 #include "intro.hpp"
00028 #include "log.hpp"
00029 #include "map_create.hpp"
00030 #include "preferences_display.hpp"
00031 #include "replay.hpp"
00032 #include "replay_controller.hpp"
00033 #include "sound.hpp"
00034 #include "tooltips.hpp"
00035 #include "video.hpp"
00036 
00037 #include <iostream>
00038 #include <iterator>
00039 
00040 #define DBG_NG LOG_STREAM(debug, engine)
00041 #define DBG_REPLAY LOG_STREAM(debug, replay)
00042 #define LOG_REPLAY LOG_STREAM(info, replay)
00043 #define ERR_REPLAY LOG_STREAM(err, replay)
00044 
00045 LEVEL_RESULT play_replay_level(const config& game_config,
00046         const config* level, CVideo& video, game_state& state_of_game)
00047 {
00048     try{
00049         const int ticks = SDL_GetTicks();
00050         const int num_turns = atoi((*level)["turns"].c_str());
00051         DBG_NG << "creating objects... " << (SDL_GetTicks() - ticks) << "\n";
00052         replay_controller replaycontroller(*level, state_of_game, ticks, num_turns, game_config, video);
00053         DBG_NG << "created objects... " << (SDL_GetTicks() - replaycontroller.get_ticks()) << "\n";
00054         const events::command_disabler disable_commands;
00055 
00056         //replay event-loop
00057         for (;;){
00058             replaycontroller.play_slice();
00059         }
00060     }
00061     catch(end_level_exception&){
00062         DBG_NG << "play_replay_level: end_level_exception\n";
00063     } catch (replay::error&) {
00064     }
00065 
00066     return LEVEL_CONTINUE;
00067 }
00068 
00069 replay_controller::replay_controller(const config& level, game_state& state_of_game,
00070                            const int ticks, const int num_turns, const config& game_config,
00071                            CVideo& video)
00072     : play_controller(level, state_of_game, ticks, num_turns, game_config, video, false, true),
00073       gamestate_start_(state_of_game), status_start_(level, num_turns, &state_of_game)
00074 {
00075     current_turn_ = 1;
00076     delay_ = 0;
00077     is_playing_ = false;
00078     show_everything_ = false;
00079     show_team_ = 1;
00080     init();
00081     gamestate_start_ = gamestate_;
00082 }
00083 
00084 replay_controller::~replay_controller(){
00085     //YogiHH
00086     //not absolutely sure if this is needed, but it makes me feel a lot better ;-)
00087     //feel free to delete this if it is not necessary
00088     gui_->get_theme().theme_reset().detach_handler(this);
00089 }
00090 
00091 bool replay_controller::continue_replay() {
00092     return !gui::dialog(*gui_,"",_("The file you have tried to load is corrupt."
00093             " Continue playing?"),gui::OK_CANCEL).show();
00094 }
00095 
00096 void replay_controller::init(){
00097     DBG_REPLAY << "in replay_controller::init()...\n";
00098 
00099     //guarantee the cursor goes back to 'normal' at the end of the level
00100     const cursor::setter cursor_setter(cursor::NORMAL);
00101     init_replay_display();
00102 
00103     try {
00104         fire_prestart(true);
00105     } catch (replay::error&) {
00106         if(!continue_replay()) {
00107             throw;
00108         }
00109     }
00110     init_gui();
00111     statistics::fresh_stats();
00112     victory_conditions::set_victory_when_enemies_defeated(
00113                         level_["victory_when_enemies_defeated"] != "no");
00114 
00115     DBG_REPLAY << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n";
00116 
00117     try {
00118         fire_start(!loading_game_);
00119     } catch (replay::error&) {
00120         if(!continue_replay()) {
00121             throw;
00122         }
00123     }
00124     update_gui();
00125 
00126     units_start_ = units_;
00127     teams_start_ = teams_;
00128 }
00129 
00130 void replay_controller::init_gui(){
00131     DBG_NG << "Initializing GUI... " << (SDL_GetTicks() - ticks_) << "\n";
00132     play_controller::init_gui();
00133 
00134     if (show_team_)
00135         gui_->set_team(show_team_ - 1, show_everything_);
00136 
00137     gui_->scroll_to_leader(units_, player_number_, display::WARP);
00138     update_locker lock_display((*gui_).video(),false);
00139     for(std::vector<team>::iterator t = teams_.begin(); t != teams_.end(); ++t) {
00140         t->reset_objectives_changed();
00141     }
00142 }
00143 
00144 void replay_controller::init_replay_display(){
00145     DBG_REPLAY << "initializing replay-display... " << (SDL_GetTicks() - ticks_) << "\n";
00146 
00147     rebuild_replay_theme();
00148     gui_->get_theme().theme_reset().attach_handler(this);
00149     DBG_REPLAY << "done initializing replay-display... " << (SDL_GetTicks() - ticks_) << "\n";
00150 }
00151 
00152 void replay_controller::rebuild_replay_theme(){
00153     const config* theme_cfg = get_theme(game_config_, level_["theme"]);
00154     if (theme_cfg) {
00155         const config* replay_theme_cfg = theme_cfg->child("resolution")->child("replay");
00156         if (NULL != replay_theme_cfg)
00157             gui_->get_theme().modify(replay_theme_cfg);
00158         //Make sure we get notified if the theme is redrawn completely. That way we have
00159         //a chance to restore the replay controls of the theme as well.
00160         gui_->invalidate_theme();
00161     }
00162 }
00163 
00164 void replay_controller::reset_replay(){
00165     gui::button* b = gui_->find_button("button-playreplay");
00166     if (b != NULL) { b->release(); }
00167     b = gui_->find_button("button-stopreplay");
00168     if (b != NULL) { b->release(); }
00169     gui_->clear_chat_messages();
00170     is_playing_ = false;
00171     player_number_ = 1;
00172     current_turn_ = 1;
00173     recorder.start_replay();
00174     units_ = units_start_;
00175     status_ = status_start_;
00176     gamestate_ = gamestate_start_;
00177     teams_ = teams_start_;
00178     statistics::fresh_stats();
00179     if (events_manager_ != NULL){
00180         delete events_manager_;
00181         events_manager_ = new game_events::manager(level_,*gui_,map_, *soundsources_manager_,
00182                                 units_,teams_, gamestate_,status_);
00183     }
00184 
00185     gui_->new_turn();
00186     gui_->invalidate_game_status();
00187     events::raise_draw_event();
00188     (*gui_).invalidate_all();
00189     (*gui_).draw();
00190 
00191     try {
00192         fire_prestart(true);
00193         fire_start(!loading_game_);
00194     } catch (replay::error&) {
00195         if(!continue_replay()) {
00196             throw;
00197         }
00198     }
00199     gui_->new_turn();
00200     gui_->invalidate_game_status();
00201     events::raise_draw_event();
00202     (*gui_).invalidate_all();
00203     (*gui_).draw();
00204     b = gui_->find_button("button-resetreplay");
00205     if (b != NULL) { b->release(); }
00206 }
00207 
00208 void replay_controller::stop_replay(){
00209     is_playing_ = false;
00210     gui::button* b = gui_->find_button("button-playreplay");
00211     if (b != NULL) { b->release(); }
00212 }
00213 
00214 void replay_controller::replay_next_turn(){
00215     is_playing_ = true;
00216     play_turn();
00217 
00218     if (!skip_replay_){
00219         gui_->scroll_to_leader(units_, player_number_);
00220     }
00221     is_playing_ = false;
00222     gui::button* b = gui_->find_button("button-nextturn");
00223     if (b != NULL) { b->release(); }
00224 }
00225 
00226 void replay_controller::replay_next_side(){
00227     is_playing_ = true;
00228     play_side(player_number_ - 1, false);
00229 
00230     if (static_cast<size_t>(player_number_) > teams_.size()) {
00231         player_number_ = 1;
00232         current_turn_++;
00233     }
00234 
00235     if (!skip_replay_) {
00236         gui_->scroll_to_leader(units_, player_number_);
00237     }
00238 
00239     is_playing_ = false;
00240     gui::button* b = gui_->find_button("button-nextside");
00241     if (b != NULL) { b->release(); }
00242 }
00243 
00244 void replay_controller::replay_show_everything(){
00245     show_everything_ = true;
00246     show_team_ = 0;
00247     update_teams();
00248     update_gui();
00249 }
00250 
00251 void replay_controller::replay_show_each(){
00252     show_everything_ = false;
00253     show_team_ = 0;
00254     update_teams();
00255     update_gui();
00256 }
00257 
00258 void replay_controller::replay_show_team1(){
00259     show_everything_ = false;
00260     show_team_ = 1;
00261     gui_->set_team(show_team_ - 1, show_everything_);
00262     update_teams();
00263     update_gui();
00264 }
00265 
00266 void replay_controller::replay_skip_animation(){
00267     recorder.set_skip(!recorder.is_skipping());
00268     skip_replay_ = !skip_replay_;
00269 }
00270 
00271 void replay_controller::play_replay(){
00272     gui::button* b = gui_->find_button("button-stopreplay");
00273     if (b != NULL) { b->release(); }
00274     if (recorder.at_end()){
00275         return;
00276     }
00277 
00278     try{
00279         is_playing_ = true;
00280 
00281         DBG_REPLAY << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";
00282         for(; !recorder.at_end() && is_playing_; first_player_ = 1) {
00283             try{
00284                 play_turn();
00285             }
00286             catch (replay::error&) //when user due to error want stop playing
00287             {
00288                 is_playing_ = false;
00289             }
00290         } //end for loop
00291         is_playing_ = false;
00292     }
00293     catch(end_level_exception& e){
00294         if (e.result == QUIT) { throw e; }
00295     }
00296 }
00297 
00298 void replay_controller::play_turn(){
00299     if (recorder.at_end()){
00300         return;
00301     }
00302 
00303     LOG_REPLAY << "turn: " << current_turn_ << "\n";
00304 
00305     gui_->new_turn();
00306     gui_->invalidate_game_status();
00307     events::raise_draw_event();
00308 
00309     bool last_team = false;
00310 
00311     while ( (!last_team) && (!recorder.at_end()) && is_playing_ ){
00312         last_team = static_cast<size_t>(player_number_) == teams_.size();
00313         play_side(player_number_ - 1, false);
00314         play_slice();
00315     }
00316 }
00317 
00318 void replay_controller::play_side(const unsigned int /*team_index*/, bool){
00319     if (recorder.at_end()){
00320         return;
00321     }
00322 
00323     DBG_REPLAY << "Status turn number: " << status_.turn() << "\n";
00324     DBG_REPLAY << "Replay_Controller turn number: " << current_turn_ << "\n";
00325     DBG_REPLAY << "Player number: " << player_number_ << "\n";
00326 
00327     // If a side is empty skip over it.
00328     if (current_team().is_empty()) return;
00329 
00330     statistics::reset_turn_stats(player_number_);
00331 
00332     try{
00333         play_controller::init_side(player_number_ - 1, true);
00334 
00335         DBG_REPLAY << "doing replay " << player_number_ << "\n";
00336         try {
00337 			::do_replay(*gui_, map_, units_, teams_,
00338                     player_number_, status_, gamestate_);
00339         } catch(replay::error&) {
00340             if(!continue_replay()) {
00341                 throw;
00342             }
00343         }
00344 
00345         finish_side_turn();
00346 
00347         // This is necessary for replays in order to show possible movements.
00348         for (unit_map::iterator uit = units_.begin(); uit != units_.end(); ++uit) {
00349             if (uit->second.side() != static_cast<size_t>(player_number_)) {
00350                 uit->second.new_turn();
00351             }
00352         }
00353 
00354         player_number_++;
00355 
00356         if (static_cast<size_t>(player_number_) > teams_.size()){
00357             status_.next_turn();
00358             finish_turn();
00359             player_number_ = 1;
00360             current_turn_++;
00361         }
00362 
00363         update_teams();
00364         update_gui();
00365     }
00366     catch (replay::error&) //if replay throws an error, we don't want to get thrown out completely
00367     {
00368         is_playing_ = false;
00369     }
00370     catch(end_level_exception& e){
00371         //VICTORY/DEFEAT end_level_exception shall not return to title screen
00372         if ((e.result != VICTORY) && (e.result != DEFEAT)) { throw e; }
00373     }
00374 }
00375 
00376 void replay_controller::update_teams(){
00377     int next_team = player_number_;
00378     if(static_cast<size_t>(next_team) > teams_.size()) {
00379         next_team = 1;
00380     }
00381 
00382     if (!show_team_)
00383         gui_->set_team(next_team - 1, show_everything_);
00384 
00385 	::clear_shroud(*gui_, map_, units_, teams_,
00386         next_team - 1);
00387     gui_->set_playing_team(next_team - 1);
00388     gui_->invalidate_all();
00389 }
00390 
00391 void replay_controller::update_gui(){
00392     (*gui_).recalculate_minimap();
00393     (*gui_).redraw_minimap();
00394     (*gui_).invalidate_all();
00395     events::raise_draw_event();
00396     (*gui_).draw();
00397 }
00398 
00399 void replay_controller::preferences(){
00400     play_controller::preferences();
00401     init_replay_display();
00402     update_gui();
00403 }
00404 
00405 void replay_controller::show_statistics(){
00406     menu_handler_.show_statistics(gui_->playing_team()+1);
00407 }
00408 
00409 void replay_controller::handle_generic_event(const std::string& /*name*/){
00410     rebuild_replay_theme();
00411 }
00412 
00413 bool replay_controller::can_execute_command(hotkey::HOTKEY_COMMAND command, int index) const
00414 {
00415     bool result = play_controller::can_execute_command(command,index);
00416 
00417     switch(command) {
00418 
00419     //commands we can always do
00420     case hotkey::HOTKEY_PLAY_REPLAY:
00421     case hotkey::HOTKEY_RESET_REPLAY:
00422     case hotkey::HOTKEY_STOP_REPLAY:
00423     case hotkey::HOTKEY_REPLAY_NEXT_TURN:
00424     case hotkey::HOTKEY_REPLAY_NEXT_SIDE:
00425     case hotkey::HOTKEY_REPLAY_SHOW_EVERYTHING:
00426     case hotkey::HOTKEY_REPLAY_SHOW_EACH:
00427     case hotkey::HOTKEY_REPLAY_SHOW_TEAM1:
00428     case hotkey::HOTKEY_REPLAY_SKIP_ANIMATION:
00429     case hotkey::HOTKEY_SAVE_GAME:
00430     case hotkey::HOTKEY_SAVE_REPLAY:
00431     case hotkey::HOTKEY_CHAT_LOG:
00432         return true;
00433 
00434     default:
00435         return result;
00436     }
00437 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs