playsingle_controller.cpp

Go to the documentation of this file.
00001 /* $Id: playsingle_controller.cpp 26242 2008-04-30 03:52:10Z alink $ */
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 //! @file playsingle_controller.cpp
00017 //! Logic for single-player game.
00018 
00019 #include "playsingle_controller.hpp"
00020 
00021 #include "construct_dialog.hpp"
00022 #include "ai_interface.hpp"
00023 #include "game_errors.hpp"
00024 #include "gettext.hpp"
00025 #include "intro.hpp"
00026 #include "log.hpp"
00027 #include "marked-up_text.hpp"
00028 #include "playturn.hpp"
00029 #include "sound.hpp"
00030 #include "upload_log.hpp"
00031 
00032 #define ERR_NG LOG_STREAM(err, engine)
00033 #define LOG_NG LOG_STREAM(info, engine)
00034 
00035 playsingle_controller::playsingle_controller(const config& level, game_state& state_of_game,
00036                                              const int ticks, const int num_turns, const config& game_config, CVideo& video,
00037                                              bool skip_replay)
00038     : play_controller(level, state_of_game, ticks, num_turns, game_config, video, skip_replay, false),
00039     cursor_setter(cursor::NORMAL), replay_sender_(recorder) , turn_over_(false)
00040 {
00041     end_turn_ = false;
00042     replaying_ = false;
00043 
00044     // game may need to start in linger mode
00045     if (state_of_game.completion == "victory" || state_of_game.completion == "defeat")
00046     {
00047         std::cerr << "Setting linger mode.\n";
00048         browse_ = linger_ = true;
00049     }
00050 }
00051 
00052 void playsingle_controller::init_gui(){
00053     LOG_NG << "Initializing GUI... " << (SDL_GetTicks() - ticks_) << "\n";
00054     play_controller::init_gui();
00055 
00056     if(first_human_team_ != -1) {
00057         gui_->scroll_to_tile(map_.starting_position(first_human_team_ + 1), game_display::WARP);
00058     }
00059     gui_->scroll_to_tile(map_.starting_position(1), game_display::WARP);
00060 
00061     update_locker lock_display(gui_->video(),recorder.is_skipping());
00062     events::raise_draw_event();
00063     gui_->draw();
00064     for(std::vector<team>::iterator t = teams_.begin(); t != teams_.end(); ++t) {
00065 		::clear_shroud(*gui_,map_,units_,teams_,(t-teams_.begin()));
00066     }
00067 }
00068 
00069 void playsingle_controller::recruit(){
00070     if (!browse_)
00071         menu_handler_.recruit(browse_, player_number_, mouse_handler_.get_last_hex());
00072 }
00073 
00074 void playsingle_controller::repeat_recruit(){
00075     if (!browse_)
00076         menu_handler_.repeat_recruit(player_number_, mouse_handler_.get_last_hex());
00077 }
00078 
00079 void playsingle_controller::recall(){
00080     if (!browse_)
00081         menu_handler_.recall(player_number_, mouse_handler_.get_last_hex());
00082 }
00083 
00084 void playsingle_controller::toggle_shroud_updates(){
00085     menu_handler_.toggle_shroud_updates(player_number_);
00086 }
00087 
00088 void playsingle_controller::update_shroud_now(){
00089     menu_handler_.update_shroud_now(player_number_);
00090 }
00091 
00092 void playsingle_controller::end_turn(){
00093     if (linger_)
00094         end_turn_ = true;
00095     else if (!browse_){
00096         end_turn_ = menu_handler_.end_turn(player_number_);
00097     }
00098 }
00099 
00100 void playsingle_controller::rename_unit(){
00101     menu_handler_.rename_unit(mouse_handler_);
00102 }
00103 
00104 void playsingle_controller::create_unit(){
00105     menu_handler_.create_unit(mouse_handler_);
00106 }
00107 
00108 void playsingle_controller::change_unit_side(){
00109     menu_handler_.change_unit_side(mouse_handler_);
00110 }
00111 
00112 void playsingle_controller::label_terrain(bool team_only){
00113     menu_handler_.label_terrain(mouse_handler_, team_only);
00114 }
00115 
00116 void playsingle_controller::continue_move(){
00117     menu_handler_.continue_move(mouse_handler_, player_number_);
00118 }
00119 
00120 void playsingle_controller::unit_hold_position(){
00121     if (!browse_)
00122         menu_handler_.unit_hold_position(mouse_handler_, player_number_);
00123 }
00124 
00125 void playsingle_controller::end_unit_turn(){
00126     if (!browse_)
00127         menu_handler_.end_unit_turn(mouse_handler_, player_number_);
00128 }
00129 
00130 void playsingle_controller::user_command(){
00131     menu_handler_.user_command();
00132 }
00133 
00134 void playsingle_controller::custom_command(){
00135     menu_handler_.custom_command(mouse_handler_, player_number_);
00136 }
00137 
00138 void playsingle_controller::ai_formula(){
00139     menu_handler_.ai_formula();
00140 }
00141 
00142 void playsingle_controller::clear_messages(){
00143     menu_handler_.clear_messages();
00144 }
00145 
00146 #ifdef USRCMD2
00147 void playsingle_controller::user_command_2(){
00148     menu_handler_.user_command_2();
00149 }
00150 
00151 void playsingle_controller::user_command_3(){
00152     menu_handler_.user_command_3();
00153 }
00154 #endif
00155 
00156 void playsingle_controller::report_victory(
00157             std::stringstream& report,
00158             end_level_exception& end_level,
00159             int player_gold,
00160             int remaining_gold, int finishing_bonus_per_turn,
00161             int turns_left, int finishing_bonus)
00162 {
00163     report << _("Remaining gold: ")
00164            << remaining_gold << "\n";
00165     if(end_level.gold_bonus) {
00166         report << _("Early finish bonus: ")
00167                << finishing_bonus_per_turn
00168                << " " << _("per turn") << "\n"
00169                << font::BOLD_TEXT << _("Turns finished early: ")
00170                << turns_left << "\n"
00171                << _("Bonus: ")
00172                << finishing_bonus << "\n"
00173                << _("Gold: ")
00174                << (remaining_gold + finishing_bonus);
00175     }
00176     report << '\n' << _("Carry over percentage: ") << end_level.carryover_percentage;
00177     if(end_level.carryover_add) {
00178         report << '\n' << font::BOLD_TEXT << _("Bonus Gold: ") << player_gold;
00179     } else {
00180         report << '\n' << font::BOLD_TEXT << _("Retained Gold: ") << player_gold;
00181     }
00182 
00183     std::string goldmsg;
00184     utils::string_map symbols;
00185     symbols["gold"] = lexical_cast_default<std::string>(player_gold);
00186     // Note that both strings are the same in english, but some languages will
00187     // want to translate them differently.
00188     if(end_level.carryover_add) {
00189         goldmsg = vngettext(
00190             "You will start the next scenario with $gold "
00191             "on top of the defined minimum starting gold.",
00192             "You will start the next scenario with $gold "
00193             "on top of the defined minimum starting gold.",
00194             player_gold, symbols);
00195 
00196     } else {
00197         goldmsg = vngettext(
00198             "You will start the next scenario with $gold "
00199             "or its defined minimum starting gold, "
00200             "whichever is higher.",
00201             "You will start the next scenario with $gold "
00202             "or its defined minimum starting gold, "
00203             "whichever is higher.",
00204             player_gold, symbols);
00205     }
00206 
00207     // xgettext:no-c-format
00208     report << '\n' << goldmsg;
00209 }
00210 
00211 LEVEL_RESULT playsingle_controller::play_scenario(const std::vector<config*>& story, upload_log& log,
00212                                                   bool skip_replay)
00213 {
00214     LOG_NG << "in playsingle_controller::play_scenario()...\n";
00215 
00216     // Start music.
00217     const config::child_list& m = level_.get_children("music");
00218     config::const_child_iterator i;
00219     for (i = m.begin(); i != m.end(); i++) {
00220         sound::play_music_config(**i);
00221     }
00222     sound::commit_music_changes();
00223 
00224     if(!skip_replay) {
00225         for(std::vector<config*>::const_iterator story_i = story.begin(); story_i != story.end(); ++story_i) {
00226 
00227             show_intro(*gui_,**story_i, level_);
00228         }
00229     }
00230     gui_->labels().read(level_, game_events::get_state_of_game());
00231 
00232     // Find a list of 'items' (i.e. overlays) on the level, and add them
00233     const config::child_list& overlays = level_.get_children("item");
00234     for(config::child_list::const_iterator overlay = overlays.begin(); overlay != overlays.end(); ++overlay) {
00235         gui_->add_overlay(gamemap::location(**overlay,game_events::get_state_of_game()),(**overlay)["image"], (**overlay)["halo"]);
00236     }
00237 
00238     victory_conditions::set_victory_when_enemies_defeated(
00239                         level_["victory_when_enemies_defeated"] != "no");
00240     victory_conditions::set_carryover_percentage(
00241         lexical_cast_default<int>(level_["carryover_percentage"],
00242         game_config::gold_carryover_percentage));
00243     victory_conditions::set_carryover_add(utils::string_bool(
00244         level_["carryover_add"], game_config::gold_carryover_add));
00245 
00246     LOG_NG << "entering try... " << (SDL_GetTicks() - ticks_) << "\n";
00247     try {
00248         // Log before prestart events: they do weird things.
00249         if (first_human_team_ != -1) {
00250             log.start(gamestate_, teams_[first_human_team_], first_human_team_ + 1, units_,
00251                       loading_game_ ? gamestate_.get_variable("turn_number") : "", status_.number_of_turns());
00252         }
00253 
00254         fire_prestart(!loading_game_);
00255         init_gui();
00256 
00257         LOG_NG << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n";
00258 
00259         fire_start(!loading_game_);
00260         gui_->recalculate_minimap();
00261 
00262         replaying_ = (recorder.at_end() == false);
00263 
00264         LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";
00265 
00266         // Initialize countdown clock.
00267         std::vector<team>::iterator t;
00268         for(t = teams_.begin(); t != teams_.end(); ++t) {
00269             std::string countd_enabled = level_["mp_countdown"].c_str();
00270             if (utils::string_bool(countd_enabled) && !loading_game_ ){
00271                 t->set_countdown_time(1000 * lexical_cast_default<int>(level_["mp_countdown_init_time"],0));
00272             }
00273         }
00274 
00275         // if we loaded a save file in linger mode, skip to it.
00276         if (linger_)
00277             throw end_level_exception(SKIP_TO_LINGER);
00278 
00279         // Avoid autosaving after loading, but still
00280         // allow the first turn to have an autosave.
00281         bool save = !loading_game_;
00282         for(; ; first_player_ = 1) {
00283             play_turn(save);
00284             save = true;
00285         } //end for loop
00286 
00287     } catch(game::load_game_exception&) {
00288         // Loading a new game is effectively a quit.
00289         log.quit(status_.turn());
00290         throw;
00291     } catch(end_level_exception& end_level) {
00292         bool obs = team_manager_.is_observer();
00293         if (game_config::exit_at_end) {
00294             exit(0);
00295         }
00296         if (end_level.result == DEFEAT || end_level.result == VICTORY) {
00297             gamestate_.completion = (end_level.result == VICTORY) ? "victory" : "defeat";
00298             recorder.set_save_info_completion(gamestate_.completion);
00299             // If we're a player, and the result is victory/defeat, then send
00300             // a message to notify the server of the reason for the game ending.
00301             if (!obs) {
00302                 config cfg;
00303                 config& info = cfg.add_child("info");
00304                 info["type"] = "termination";
00305                 info["condition"] = "game over";
00306                 info["result"] = gamestate_.completion;
00307                 network::send_data(cfg, 0, true);
00308             } else {
00309                 gui::message_dialog(*gui_,_("Game Over"),
00310                                     _("The game is over.")).show();
00311                 return OBSERVER_END;
00312             }
00313         }
00314 
00315         if(end_level.result == QUIT) {
00316             log.quit(status_.turn());
00317             return end_level.result;
00318         } else if(end_level.result == DEFEAT) {
00319             gamestate_.completion = "defeat";
00320             log.defeat(status_.turn());
00321             try {
00322                 game_events::fire("defeat");
00323             } catch(end_level_exception&) {
00324             }
00325 
00326             if (!obs)
00327                 return DEFEAT;
00328             else
00329                 return QUIT;
00330         } else if (end_level.result == VICTORY
00331         || end_level.result == LEVEL_CONTINUE
00332         || end_level.result == LEVEL_CONTINUE_NO_SAVE) {
00333             if(end_level.result == LEVEL_CONTINUE_NO_SAVE) {
00334                 gamestate_.completion = "running";
00335             } else {
00336                 gamestate_.completion = "victory";
00337             }
00338             recorder.set_save_info_completion(gamestate_.completion);
00339             try {
00340                 game_events::fire("victory");
00341             } catch(end_level_exception&) {
00342             }
00343             if (first_human_team_ != -1)
00344                 log.victory(status_.turn(), teams_[first_human_team_].gold());
00345 
00346             const bool has_next_scenario = !gamestate_.next_scenario.empty() &&
00347                                             gamestate_.next_scenario != "null";
00348 
00349             // Save current_player name to reuse it when setting next_scenario side info
00350             std::vector<team>::iterator i;
00351             for (i = teams_.begin(); i != teams_.end(); ++i) {
00352                 player_info *player=gamestate_.get_player(i->save_id());
00353                 if (player)
00354                     player->name = i->current_player();
00355             }
00356 
00357             // Add all the units that survived the scenario.
00358             for(unit_map::iterator un = units_.begin(); un != units_.end(); ++un) {
00359                 player_info *player=gamestate_.get_player(teams_[un->second.side()-1].save_id());
00360 
00361                 if(player) {
00362                     un->second.new_turn();
00363                     un->second.new_level();
00364                     player->available_units.push_back(un->second);
00365                 }
00366             }
00367 
00368             // 'continue' is like a victory, except it doesn't announce victory,
00369             // and the player retains 100% of gold.
00370             if(end_level.result == LEVEL_CONTINUE || end_level.result == LEVEL_CONTINUE_NO_SAVE) {
00371                 for(i=teams_.begin(); i!=teams_.end(); ++i) {
00372                     player_info *player=gamestate_.get_player(i->save_id());
00373                     if(player) {
00374                         player->gold = i->gold();
00375                     }
00376                 }
00377 
00378                 return end_level.result == LEVEL_CONTINUE_NO_SAVE ? LEVEL_CONTINUE_NO_SAVE : VICTORY;
00379             }
00380 
00381             std::stringstream report;
00382             std::string title;
00383 
00384             if (obs) {
00385                 title = _("Scenario Report");
00386             } else {
00387                 title = _("Victory");
00388                 report << font::BOLD_TEXT << _("You have emerged victorious!") << "\n~\n";
00389             }
00390             if (gamestate_.players.size() > 0 &&
00391                      (has_next_scenario ||
00392                      gamestate_.campaign_type == "test")) {
00393                 const int finishing_bonus_per_turn =
00394                          map_.villages().size() * game_config::village_income +
00395                          game_config::base_income;
00396                 const int turns_left = maximum<int>(0,status_.number_of_turns() - status_.turn());
00397                 const int finishing_bonus = end_level.gold_bonus ?
00398                          (finishing_bonus_per_turn * turns_left) : 0;
00399 
00400                 for(i=teams_.begin(); i!=teams_.end(); ++i) {
00401                     player_info *player=gamestate_.get_player(i->save_id());
00402 
00403                     if (player) {
00404                         // Store the gold for all players.
00405                         player->gold = ((i->gold() + finishing_bonus)
00406                                 * end_level.carryover_percentage) / 100;
00407                         player->gold_add = end_level.carryover_add;
00408 
00409                         // Only show the report for ourselves.
00410                         if (!i->is_persistent())
00411                             continue;
00412 
00413                         if(gamestate_.players.size()>1) {
00414                             if(i!=teams_.begin()) {
00415                                 report << "\n";
00416                             }
00417 
00418                             report << font::BOLD_TEXT << i->current_player() << "\n";
00419                         }
00420 
00421                         report_victory(report, end_level, player->gold, i->gold(), finishing_bonus_per_turn, turns_left, finishing_bonus);
00422                     }
00423                 }
00424             }
00425 
00426             gui::message_dialog(*gui_, title, report.str()).show();
00427 
00428             return VICTORY;
00429         } else if (end_level.result == SKIP_TO_LINGER) {
00430             LOG_NG << "resuming from loaded linger state...\n";
00431             return VICTORY;
00432         }
00433     } // end catch
00434     catch(replay::error&) {
00435         gui::message_dialog(*gui_,"",_("The file you have tried to load is corrupt")).show();
00436         return QUIT;
00437     }
00438     catch(network::error& e) {
00439         bool disconnect = false;
00440         if(e.socket) {
00441             e.disconnect();
00442             disconnect = true;
00443         }
00444 
00445         menu_handler_.save_game(_("A network disconnection has occurred, and the game cannot continue. Do you want to save the game?"),gui::YES_NO);
00446         if(disconnect) {
00447             throw network::error();
00448         } else {
00449             return QUIT;
00450         }
00451     }
00452 
00453     return QUIT;
00454 }
00455 
00456 void playsingle_controller::play_turn(bool save)
00457 {
00458     gui_->new_turn();
00459     gui_->invalidate_game_status();
00460     events::raise_draw_event();
00461 
00462     LOG_NG << "turn: " << status_.turn() << "\n";
00463 
00464     if(non_interactive())
00465         std::cout << "Turn " << status_.turn() << ":" << std::endl;
00466 
00467 
00468     for(player_number_ = first_player_; player_number_ <= teams_.size(); player_number_++) {
00469         // If a side is empty skip over it.
00470         if (current_team().is_empty()) continue;
00471 
00472         init_side(player_number_ - 1);
00473 
00474         if (replaying_) {
00475             LOG_NG << "doing replay " << player_number_ << "\n";
00476             try {
00477                 replaying_ = ::do_replay(*gui_, map_, units_, teams_,
00478                         player_number_, status_, gamestate_);
00479             } catch(replay::error&) {
00480                 gui::message_dialog(*gui_,"",_("The file you have tried to load is corrupt")).show();
00481 
00482                 replaying_ = false;
00483             }
00484             LOG_NG << "result of replay: " << (replaying_?"true":"false") << "\n";
00485         } else {
00486             // If a side is dead end the turn.
00487             if ((current_team().is_human() && team_units(units_, player_number_) == 0))
00488             {
00489                 turn_info turn_data(gamestate_, status_, *gui_, map_,
00490                         teams_, player_number_, units_, replay_sender_, undo_stack_);
00491                 recorder.end_turn();
00492                 turn_data.sync_network();
00493                 continue;
00494             }
00495             play_side(player_number_, save);
00496         }
00497 
00498         finish_side_turn();
00499 
00500         if(non_interactive()) {
00501             std::cout << " Player " << player_number_ << ": " <<
00502                 current_team().villages().size() << " Villages" <<
00503                 std::endl;
00504         }
00505 
00506         check_victory(units_, teams_, *gui_);
00507     }
00508 
00509     // Time has run out
00510     check_time_over();
00511 
00512     finish_turn();
00513 }
00514 
00515 void playsingle_controller::play_side(const unsigned int team_index, bool save)
00516 {
00517     do {
00518         // Although this flag is used only in this method,
00519         // it has to be a class member since derived classes
00520         // rely on it
00521         player_type_changed_ = false;
00522         end_turn_ = false;
00523 
00524         statistics::reset_turn_stats(player_number_);
00525 
00526         if(current_team().is_human()) {
00527             LOG_NG << "is human...\n";
00528             try{
00529                 before_human_turn(save);
00530                 play_human_turn();
00531                 after_human_turn();
00532             } catch(end_turn_exception& end_turn) {
00533                 if (end_turn.redo == team_index) {
00534                     player_type_changed_ = true;
00535                     // If new controller is not human,
00536                     // reset gui to prev human one
00537                     if (!teams_[team_index-1].is_human()) {
00538                         int t = find_human_team_before(team_index);
00539                         if (t > 0) {
00540                             gui_->set_team(t-1);
00541                             gui_->recalculate_minimap();
00542                             gui_->invalidate_all();
00543                             gui_->draw(true,true);
00544                         }
00545                     }
00546                 }
00547             }
00548 
00549             if(game_config::debug)
00550                 game_display::clear_debug_highlights();
00551 
00552             LOG_NG << "human finished turn...\n";
00553         } else if(current_team().is_ai()) {
00554             play_ai_turn();
00555         }
00556     } while (player_type_changed_);
00557     // Keep looping if the type of a team (human/ai/networked)
00558     // has changed mid-turn
00559 }
00560 
00561 void playsingle_controller::before_human_turn(bool save)
00562 {
00563     log_scope("player turn");
00564     browse_ = false;
00565     linger_ = false;
00566 
00567     gui_->set_team(player_number_ - 1);
00568     gui_->recalculate_minimap();
00569     gui_->invalidate_all();
00570     gui_->draw(true,true);
00571 
00572     if (save) {
00573         menu_handler_.autosave(gamestate_.label, status_.turn(), gamestate_.starting_pos);
00574     }
00575 
00576     if(preferences::turn_bell()) {
00577         sound::play_bell(game_config::sounds::turn_bell);
00578     }
00579 
00580     if(preferences::turn_dialog()) {
00581         std::string message = _("It is now $name|'s turn");
00582         utils::string_map symbols;
00583         symbols["name"] = teams_[player_number_ - 1].current_player();
00584         message = utils::interpolate_variables_into_string(message, &symbols);
00585         gui::message_dialog(*gui_, "", message).show();
00586     }
00587 
00588     // Execute goto-movements - first collect gotos in a list
00589     std::vector<gamemap::location> gotos;
00590 
00591     for(unit_map::iterator ui = units_.begin(); ui != units_.end(); ++ui) {
00592         if(ui->second.get_goto() == ui->first)
00593             ui->second.set_goto(gamemap::location());
00594 
00595         if(ui->second.side() == player_number_ && map_.on_board(ui->second.get_goto()))
00596             gotos.push_back(ui->first);
00597     }
00598 
00599     for(std::vector<gamemap::location>::const_iterator g = gotos.begin(); g != gotos.end(); ++g) {
00600         unit_map::const_iterator ui = units_.find(*g);
00601         menu_handler_.move_unit_to_loc(ui,ui->second.get_goto(),false, player_number_, mouse_handler_);
00602     }
00603 
00604     // erase the footsteps after movement
00605     gui_->set_route(NULL);
00606 }
00607 
00608 void playsingle_controller::play_human_turn(){
00609     gui_->enable_menu("endturn", true);
00610     while(!end_turn_) {
00611         play_slice();
00612         gui_->draw();
00613     }
00614 }
00615 
00616 void playsingle_controller::linger(upload_log& log)
00617 {
00618     LOG_NG << "beginning end-of-scenario linger\n";
00619     browse_ = true;
00620     linger_ = true;
00621 
00622     // If we need to set the status depending on the completion state
00623     // the key to it is here.
00624     gui_->set_game_mode(game_display::LINGER_SP);
00625 
00626     // this is actually for after linger mode is over -- we don't
00627     // want to stay stuck in linger state when the *next* scenario
00628     // is over.
00629     gamestate_.completion = "running";
00630 
00631     // change the end-turn button text to its alternate label
00632     gui_->get_theme().refresh_title2(std::string("button-endturn"), std::string("title2"));
00633     gui_->invalidate_theme();
00634     gui_->redraw_everything();
00635 
00636     // End all unit moves
00637     for (unit_map::iterator u = units_.begin(); u != units_.end(); u++) {
00638         u->second.set_user_end_turn(true);
00639     }
00640     try {
00641         // Same logic as single-player human turn, but
00642         // *not* the same as multiplayer human turn.
00643         gui_->enable_menu("endturn", true);
00644         while(!end_turn_) {
00645             // Reset the team number to make sure we're the right team.
00646             player_number_ = first_player_;
00647             play_slice();
00648 
00649             gui_->draw();
00650         }
00651     } catch(game::load_game_exception&) {
00652         // Loading a new game is effectively a quit.
00653         log.quit(status_.turn());
00654         throw;
00655     }
00656 
00657     // revert the end-turn button text to its normal label
00658     gui_->get_theme().refresh_title2(std::string("button-endturn"), std::string("title"));
00659     gui_->invalidate_theme();
00660     gui_->redraw_everything();
00661     gui_->set_game_mode(game_display::RUNNING);
00662 
00663     LOG_NG << "ending end-of-scenario linger\n";
00664 }
00665 
00666 void playsingle_controller::end_turn_record()
00667 {
00668     if (!turn_over_)
00669     {
00670         turn_over_ = true;
00671         recorder.end_turn();
00672     }
00673 }
00674 void playsingle_controller::end_turn_record_unlock()
00675 {
00676     turn_over_ = false;
00677 }
00678 
00679 void playsingle_controller::after_human_turn(){
00680     end_turn_record();
00681     end_turn_record_unlock();
00682     menu_handler_.clear_undo_stack(player_number_);
00683 
00684     if(teams_[player_number_-1].uses_fog()) {
00685         // needed because currently fog is only recalculated when a hex is /un/covered
00686         recalculate_fog(map_,units_,teams_,player_number_-1);
00687     }
00688 
00689     gui_->set_route(NULL);
00690     gui_->unhighlight_reach();
00691 }
00692 
00693 void playsingle_controller::play_ai_turn(){
00694     LOG_NG << "is ai...\n";
00695     gui_->enable_menu("endturn", false);
00696     browse_ = true;
00697     gui_->recalculate_minimap();
00698 
00699     const cursor::setter cursor_setter(cursor::WAIT);
00700 
00701     turn_info turn_data(gamestate_,status_,*gui_,
00702             map_, teams_, player_number_, units_, replay_sender_, undo_stack_);
00703 
00704     ai_interface::info ai_info(*gui_,map_,units_,teams_,player_number_,status_, turn_data, gamestate_);
00705     util::scoped_ptr<ai_interface> ai_obj(create_ai(current_team().ai_algorithm(),ai_info));
00706     ai_obj->user_interact().attach_handler(this);
00707     ai_obj->unit_recruited().attach_handler(this);
00708     ai_obj->unit_moved().attach_handler(this);
00709     ai_obj->enemy_attacked().attach_handler(this);
00710     ai_obj->play_turn();
00711     recorder.end_turn();
00712     turn_data.sync_network();
00713 
00714     gui_->recalculate_minimap();
00715 	::clear_shroud(*gui_,map_,units_,teams_,player_number_-1);
00716     gui_->invalidate_unit();
00717     gui_->invalidate_game_status();
00718     gui_->invalidate_all();
00719     gui_->draw();
00720     gui_->delay(100);
00721 }
00722 
00723 void playsingle_controller::handle_generic_event(const std::string& name){
00724     if (name == "ai_user_interact"){
00725         play_slice();
00726         gui_->draw();
00727     }
00728 }
00729 
00730 void playsingle_controller::check_time_over(){
00731     if(!status_.next_turn()) {
00732 
00733         if(non_interactive()) {
00734             std::cout << "time over (draw)\n";
00735         }
00736 
00737         LOG_NG << "firing time over event...\n";
00738         game_events::fire("time over");
00739         LOG_NG << "done firing time over event...\n";
00740 
00741         throw end_level_exception(DEFEAT);
00742     }
00743 }
00744 
00745 bool playsingle_controller::can_execute_command(hotkey::HOTKEY_COMMAND command, int index) const
00746 {
00747     bool res = true;
00748     switch (command){
00749         case hotkey::HOTKEY_UNIT_HOLD_POSITION:
00750         case hotkey::HOTKEY_END_UNIT_TURN:
00751         case hotkey::HOTKEY_RECRUIT:
00752         case hotkey::HOTKEY_REPEAT_RECRUIT:
00753         case hotkey::HOTKEY_RECALL:
00754             return !browse_ && !linger_ && !events::commands_disabled;
00755         case hotkey::HOTKEY_ENDTURN:
00756             return (!browse_ || linger_) && !events::commands_disabled;
00757 
00758         case hotkey::HOTKEY_DELAY_SHROUD:
00759             return !linger_ && (current_team().uses_fog() || current_team().uses_shroud());
00760         case hotkey::HOTKEY_UPDATE_SHROUD:
00761             return !linger_ && !events::commands_disabled && current_team().auto_shroud_updates() == false;
00762 
00763         // Commands we can only do if in debug mode
00764         case hotkey::HOTKEY_CREATE_UNIT:
00765         case hotkey::HOTKEY_CHANGE_UNIT_SIDE:
00766             return !events::commands_disabled && game_config::debug && map_.on_board(mouse_handler_.get_last_hex());
00767 
00768         case hotkey::HOTKEY_LABEL_TEAM_TERRAIN:
00769         case hotkey::HOTKEY_LABEL_TERRAIN:
00770             res = !events::commands_disabled && map_.on_board(mouse_handler_.get_last_hex())
00771                 && !gui_->shrouded(mouse_handler_.get_last_hex())
00772                 && !is_observer();
00773             break;
00774 
00775         case hotkey::HOTKEY_CONTINUE_MOVE: {
00776             if(browse_ || events::commands_disabled)
00777                 return false;
00778 
00779             if( (menu_handler_.current_unit(mouse_handler_) != units_.end())
00780                 && (menu_handler_.current_unit(mouse_handler_)->second.move_interrupted()))
00781                 return true;
00782             const unit_map::const_iterator i = units_.find(mouse_handler_.get_selected_hex());
00783             if (i == units_.end()) return false;
00784             return i->second.move_interrupted();
00785         }
00786         default: return play_controller::can_execute_command(command, index);
00787     }
00788     return res;
00789 }

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