00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "global.hpp"
00018
00019 #include "foreach.hpp"
00020 #include "game_end_exceptions.hpp"
00021 #include "game_events.hpp"
00022 #include "gettext.hpp"
00023 #include "log.hpp"
00024 #include "map_label.hpp"
00025 #include "replay.hpp"
00026 #include "replay_controller.hpp"
00027 #include "resources.hpp"
00028 #include "savegame.hpp"
00029
00030 static lg::log_domain log_engine("engine");
00031 #define DBG_NG LOG_STREAM(debug, log_engine)
00032
00033 static lg::log_domain log_replay("replay");
00034 #define DBG_REPLAY LOG_STREAM(debug, log_replay)
00035 #define LOG_REPLAY LOG_STREAM(info, log_replay)
00036
00037 LEVEL_RESULT play_replay_level(const config& game_config,
00038 const config* level, CVideo& video, game_state& state_of_game)
00039 {
00040 try{
00041 const int ticks = SDL_GetTicks();
00042 int num_turns = (*level)["turns"].to_int(-1);
00043 DBG_NG << "creating objects... " << (SDL_GetTicks() - ticks) << "\n";
00044 replay_controller replaycontroller(*level, state_of_game, ticks, num_turns, game_config, video);
00045 DBG_NG << "created objects... " << (SDL_GetTicks() - replaycontroller.get_ticks()) << "\n";
00046 const events::command_disabler disable_commands;
00047
00048
00049 for (;;){
00050 replaycontroller.play_slice();
00051 }
00052 }
00053 catch(end_level_exception&){
00054 DBG_NG << "play_replay_level: end_level_exception\n";
00055 }
00056
00057 return VICTORY;
00058 }
00059
00060 replay_controller::replay_controller(const config& level,
00061 game_state& state_of_game, const int ticks, const int num_turns,
00062 const config& game_config, CVideo& video) :
00063 play_controller(level, state_of_game, ticks, num_turns, game_config, video, false),
00064 teams_start_(),
00065 gamestate_start_(gamestate_),
00066 units_start_(),
00067 tod_manager_start_(level, num_turns),
00068 current_turn_(1),
00069 delay_(0),
00070 is_playing_(false),
00071 show_everything_(false),
00072 show_team_(state_of_game.classification().campaign_type == "multiplayer" ? 0 : 1)
00073 {
00074 units_start_ = units_;
00075 teams_start_ = teams_;
00076 tod_manager_start_ = tod_manager_;
00077
00078 init();
00079 reset_replay();
00080 }
00081
00082 replay_controller::~replay_controller()
00083 {
00084
00085
00086
00087 gui_->get_theme().theme_reset_event().detach_handler(this);
00088 gui_->complete_redraw_event().detach_handler(this);
00089 }
00090
00091 void replay_controller::init(){
00092 DBG_REPLAY << "in replay_controller::init()...\n";
00093
00094
00095 const cursor::setter cursor_setter(cursor::NORMAL);
00096 init_replay_display();
00097 }
00098
00099 void replay_controller::init_gui(){
00100 DBG_NG << "Initializing GUI... " << (SDL_GetTicks() - ticks_) << "\n";
00101 play_controller::init_gui();
00102
00103 if (show_team_)
00104 gui_->set_team(show_team_ - 1, show_everything_);
00105 else
00106 gui_->set_team(0, show_everything_);
00107
00108 gui_->scroll_to_leader(units_, player_number_, display::WARP);
00109 update_locker lock_display((*gui_).video(),false);
00110 for(std::vector<team>::iterator t = teams_.begin(); t != teams_.end(); ++t) {
00111 t->reset_objectives_changed();
00112 }
00113
00114 update_replay_ui();
00115 }
00116
00117 void replay_controller::init_replay_display(){
00118 DBG_REPLAY << "initializing replay-display... " << (SDL_GetTicks() - ticks_) << "\n";
00119
00120 rebuild_replay_theme();
00121 gui_->get_theme().theme_reset_event().attach_handler(this);
00122 gui_->complete_redraw_event().attach_handler(this);
00123 DBG_REPLAY << "done initializing replay-display... " << (SDL_GetTicks() - ticks_) << "\n";
00124 }
00125
00126 void replay_controller::rebuild_replay_theme()
00127 {
00128 const config &theme_cfg = get_theme(game_config_, level_["theme"]);
00129 if (const config &res = theme_cfg.child("resolution"))
00130 {
00131 if (const config &replay_theme_cfg = res.child("replay"))
00132 gui_->get_theme().modify(replay_theme_cfg);
00133 gui_->get_theme().modify_label("time-icon", _ ("current local time"));
00134
00135
00136 gui_->invalidate_theme();
00137 }
00138 }
00139
00140 gui::button* replay_controller::play_button()
00141 {
00142 return gui_->find_button("button-playreplay");
00143 }
00144
00145 gui::button* replay_controller::stop_button()
00146 {
00147 return gui_->find_button("button-stopreplay");
00148 }
00149
00150 gui::button* replay_controller::reset_button()
00151 {
00152 return gui_->find_button("button-resetreplay");
00153 }
00154
00155 gui::button* replay_controller::play_turn_button()
00156 {
00157 return gui_->find_button("button-nextturn");
00158 }
00159
00160 gui::button* replay_controller::play_side_button()
00161 {
00162 return gui_->find_button("button-nextside");
00163 }
00164
00165 void replay_controller::update_replay_ui()
00166 {
00167
00168
00169 if(!replay_ui_has_all_buttons()) {
00170 gui::button *play_b = play_button(), *stop_b = stop_button(),
00171 *reset_b = reset_button(), *play_turn_b = play_turn_button(),
00172 *play_side_b = play_side_button();
00173
00174 if(play_b) {
00175 play_b->enable(false);
00176 }
00177
00178 if(stop_b) {
00179 stop_b->enable(false);
00180 }
00181
00182 if(reset_b) {
00183 reset_b->enable(false);
00184 }
00185
00186 if(play_turn_b) {
00187 play_turn_b->enable(false);
00188 }
00189
00190 if(play_side_b) {
00191 play_side_b->enable(false);
00192 }
00193 }
00194 }
00195
00196 void replay_controller::replay_ui_playback_should_start()
00197 {
00198 if(!replay_ui_has_all_buttons())
00199 return;
00200
00201 play_button()->enable(false);
00202 reset_button()->enable(false);
00203 play_turn_button()->enable(false);
00204 play_side_button()->enable(false);
00205 }
00206
00207 void replay_controller::replay_ui_playback_should_stop()
00208 {
00209 if(!replay_ui_has_all_buttons())
00210 return;
00211
00212 if(!recorder.at_end()) {
00213 play_button()->enable(true);
00214 reset_button()->enable(true);
00215 play_turn_button()->enable(true);
00216 play_side_button()->enable(true);
00217
00218 play_button()->release();
00219 play_turn_button()->release();
00220 play_side_button()->release();
00221 } else {
00222 reset_button()->enable(true);
00223 stop_button()->enable(false);
00224 }
00225
00226 if(!is_playing_) {
00227
00228 stop_button()->release();
00229 }
00230 }
00231
00232 void replay_controller::reset_replay_ui()
00233 {
00234 if(!replay_ui_has_all_buttons())
00235 return;
00236
00237 play_button()->enable(true);
00238 stop_button()->enable(true);
00239 reset_button()->enable(true);
00240 play_turn_button()->enable(true);
00241 play_side_button()->enable(true);
00242 }
00243
00244
00245 void replay_controller::reset_replay(){
00246
00247 gui_->clear_chat_messages();
00248 is_playing_ = false;
00249 player_number_ = 1;
00250 current_turn_ = 1;
00251 it_is_a_new_turn_ = true;
00252 skip_replay_ = false;
00253 tod_manager_= tod_manager_start_;
00254 recorder.start_replay();
00255 recorder.set_skip(false);
00256 units_ = units_start_;
00257 gamestate_ = gamestate_start_;
00258 teams_ = teams_start_;
00259 if (events_manager_ ){
00260
00261
00262
00263
00264 events_manager_.reset();
00265 events_manager_.reset(new game_events::manager(level_));
00266 }
00267
00268 gui_->labels().read(level_);
00269
00270 statistics::fresh_stats();
00271 set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true));
00272
00273
00274 if (const config &era_cfg = level_.child("era")) {
00275 game_events::add_events(era_cfg.child_range("event"), "era_events");
00276 }
00277
00278 fire_prestart(true);
00279 init_gui();
00280 fire_start(true);
00281 update_gui();
00282
00283 reset_replay_ui();
00284 }
00285
00286 void replay_controller::stop_replay(){
00287 is_playing_ = false;
00288 }
00289
00290 void replay_controller::replay_next_turn(){
00291 is_playing_ = true;
00292 replay_ui_playback_should_start();
00293
00294 play_turn();
00295
00296 if (!skip_replay_ || !is_playing_){
00297 gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false);
00298 }
00299
00300 replay_ui_playback_should_stop();
00301 }
00302
00303 void replay_controller::replay_next_side(){
00304 is_playing_ = true;
00305 replay_ui_playback_should_start();
00306
00307 play_side(player_number_ - 1, false);
00308
00309 if (!skip_replay_ || !is_playing_) {
00310 gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false);
00311 }
00312
00313 replay_ui_playback_should_stop();
00314 }
00315
00316 void replay_controller::process_oos(const std::string& msg) const
00317 {
00318 if (game_config::ignore_replay_errors) return;
00319
00320 std::stringstream message;
00321 message << _("The replay is corrupt/out of sync. It might not make much sense to continue. Do you want to save the game?");
00322 message << "\n\n" << _("Error details:") << "\n\n" << msg;
00323
00324 savegame::oos_savegame save(to_config());
00325 save.save_game_interactive(resources::screen->video(), message.str(), gui::YES_NO);
00326 }
00327
00328 void replay_controller::replay_show_everything(){
00329 show_everything_ = true;
00330 show_team_ = 0;
00331 update_teams();
00332 update_gui();
00333 }
00334
00335 void replay_controller::replay_show_each(){
00336 show_everything_ = false;
00337 show_team_ = 0;
00338 update_teams();
00339 update_gui();
00340 }
00341
00342 void replay_controller::replay_show_team1(){
00343 show_everything_ = false;
00344 show_team_ = 1;
00345 update_teams();
00346 update_gui();
00347 }
00348
00349 void replay_controller::replay_skip_animation(){
00350 skip_replay_ = !skip_replay_;
00351 recorder.set_skip(skip_replay_);
00352 }
00353
00354
00355 void replay_controller::play_replay(){
00356
00357 if (recorder.at_end()){
00358
00359 return;
00360 }
00361
00362 try{
00363 is_playing_ = true;
00364 replay_ui_playback_should_start();
00365
00366 DBG_REPLAY << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";
00367 for(; !recorder.at_end() && is_playing_; first_player_ = 1) {
00368 play_turn();
00369 }
00370
00371 if (!is_playing_) {
00372 gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false);
00373 }
00374 }
00375 catch(end_level_exception& e){
00376 if (e.result == QUIT) throw;
00377 }
00378
00379 replay_ui_playback_should_stop();
00380 }
00381
00382
00383 void replay_controller::play_turn(){
00384
00385 LOG_REPLAY << "turn: " << current_turn_ << "\n";
00386
00387 gui_->new_turn();
00388 gui_->invalidate_game_status();
00389 events::raise_draw_event();
00390
00391 bool last_team = false;
00392
00393 while ( (!last_team) && (!recorder.at_end()) && is_playing_ ){
00394 last_team = static_cast<size_t>(player_number_) == teams_.size();
00395 play_side(player_number_ - 1, false);
00396 play_slice();
00397 }
00398 }
00399
00400
00401 void replay_controller::play_side(const unsigned int , bool){
00402
00403 DBG_REPLAY << "Status turn number: " << turn() << "\n";
00404 DBG_REPLAY << "Replay_Controller turn number: " << current_turn_ << "\n";
00405 DBG_REPLAY << "Player number: " << player_number_ << "\n";
00406
00407 try{
00408
00409 if (!current_team().is_empty()) {
00410 statistics::reset_turn_stats(current_team().save_id());
00411
00412 play_controller::init_side(player_number_ - 1, true);
00413
00414 DBG_REPLAY << "doing replay " << player_number_ << "\n";
00415 do_replay(player_number_);
00416
00417 finish_side_turn();
00418 }
00419
00420 player_number_++;
00421
00422 if (static_cast<size_t>(player_number_) > teams_.size()) {
00423 finish_turn();
00424 tod_manager_.next_turn();
00425 it_is_a_new_turn_ = true;
00426 player_number_ = 1;
00427 current_turn_++;
00428 gui_->new_turn();
00429 }
00430
00431
00432 foreach (unit &u, units_) {
00433 if (u.side() == player_number_) {
00434 u.new_turn();
00435 }
00436 }
00437
00438 update_teams();
00439 update_gui();
00440 }
00441 catch(end_level_exception& e){
00442
00443 if (e.result != VICTORY && e.result != DEFEAT) throw;
00444 }
00445 }
00446
00447 void replay_controller::update_teams(){
00448
00449 int next_team = player_number_;
00450 if(static_cast<size_t>(next_team) > teams_.size()) {
00451 next_team = 1;
00452 }
00453
00454 if (!show_team_) {
00455 gui_->set_team(next_team - 1, show_everything_);
00456 } else {
00457 gui_->set_team(show_team_ - 1, show_everything_);
00458 }
00459
00460 clear_shroud(next_team);
00461
00462 gui_->set_playing_team(next_team - 1);
00463 gui_->invalidate_all();
00464 }
00465
00466 void replay_controller::update_gui(){
00467 (*gui_).recalculate_minimap();
00468 (*gui_).redraw_minimap();
00469 (*gui_).invalidate_all();
00470 events::raise_draw_event();
00471 (*gui_).draw();
00472 }
00473
00474 void replay_controller::preferences(){
00475 play_controller::preferences();
00476 update_gui();
00477 }
00478
00479 void replay_controller::show_statistics(){
00480 menu_handler_.show_statistics(gui_->playing_team()+1);
00481 }
00482
00483 void replay_controller::handle_generic_event(const std::string& name){
00484
00485 if( name == "completely_redrawn" ) {
00486 update_replay_ui();
00487
00488 gui::button* skip_animation_button = gui_->find_button("skip-animation");
00489 if(skip_animation_button) {
00490 skip_animation_button->set_check(skip_replay_);
00491 }
00492 } else {
00493 rebuild_replay_theme();
00494 }
00495 }
00496
00497 bool replay_controller::can_execute_command(hotkey::HOTKEY_COMMAND command, int index) const
00498 {
00499 bool result = play_controller::can_execute_command(command,index);
00500
00501 switch(command) {
00502
00503
00504 case hotkey::HOTKEY_PLAY_REPLAY:
00505 case hotkey::HOTKEY_RESET_REPLAY:
00506 case hotkey::HOTKEY_STOP_REPLAY:
00507 case hotkey::HOTKEY_REPLAY_NEXT_TURN:
00508 case hotkey::HOTKEY_REPLAY_NEXT_SIDE:
00509 case hotkey::HOTKEY_REPLAY_SHOW_EVERYTHING:
00510 case hotkey::HOTKEY_REPLAY_SHOW_EACH:
00511 case hotkey::HOTKEY_REPLAY_SHOW_TEAM1:
00512 case hotkey::HOTKEY_REPLAY_SKIP_ANIMATION:
00513 case hotkey::HOTKEY_SAVE_GAME:
00514 case hotkey::HOTKEY_SAVE_REPLAY:
00515 case hotkey::HOTKEY_CHAT_LOG:
00516 return true;
00517
00518 default:
00519 return result;
00520 }
00521 }