00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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
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
00086
00087
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
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
00159
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&)
00287 {
00288 is_playing_ = false;
00289 }
00290 }
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 , 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
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
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&)
00367 {
00368 is_playing_ = false;
00369 }
00370 catch(end_level_exception& e){
00371
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& ){
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
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 }