00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "playsingle_controller.hpp"
00024
00025 #include "actions.hpp"
00026 #include "ai/manager.hpp"
00027 #include "ai/game_info.hpp"
00028 #include "ai/testing.hpp"
00029 #include "dialogs.hpp"
00030 #include "foreach.hpp"
00031 #include "game_end_exceptions.hpp"
00032 #include "game_events.hpp"
00033 #include "game_preferences.hpp"
00034 #include "gettext.hpp"
00035 #include "gui/dialogs/transient_message.hpp"
00036 #include "log.hpp"
00037 #include "map_label.hpp"
00038 #include "marked-up_text.hpp"
00039 #include "playturn.hpp"
00040 #include "resources.hpp"
00041 #include "savegame.hpp"
00042 #include "sound.hpp"
00043 #include "formula_string_utils.hpp"
00044 #include "events.hpp"
00045 #include "save_blocker.hpp"
00046 #include "soundsource.hpp"
00047 #include "storyscreen/interface.hpp"
00048 #include "whiteboard/manager.hpp"
00049 #include "util.hpp"
00050
00051 static lg::log_domain log_engine("engine");
00052 #define ERR_NG LOG_STREAM(err, log_engine)
00053 #define LOG_NG LOG_STREAM(info, log_engine)
00054
00055 playsingle_controller::playsingle_controller(const config& level,
00056 game_state& state_of_game, const int ticks, const int num_turns,
00057 const config& game_config, CVideo& video, bool skip_replay) :
00058 play_controller(level, state_of_game, ticks, num_turns, game_config, video, skip_replay),
00059 cursor_setter(cursor::NORMAL),
00060 data_backlog_(),
00061 textbox_info_(),
00062 replay_sender_(recorder),
00063 end_turn_(false),
00064 player_type_changed_(false),
00065 replaying_(false),
00066 turn_over_(false),
00067 skip_next_turn_(false),
00068 level_result_(NONE)
00069 {
00070
00071 if (state_of_game.classification().completion == "victory" || state_of_game.classification().completion == "defeat")
00072 {
00073 LOG_NG << "Setting linger mode.\n";
00074 browse_ = linger_ = true;
00075 }
00076
00077 ai::game_info ai_info;
00078 ai::manager::set_ai_info(ai_info);
00079 ai::manager::add_observer(this) ;
00080 }
00081
00082 playsingle_controller::~playsingle_controller()
00083 {
00084 ai::manager::remove_observer(this) ;
00085 ai::manager::clear_ais() ;
00086 }
00087
00088 void playsingle_controller::init_gui(){
00089 LOG_NG << "Initializing GUI... " << (SDL_GetTicks() - ticks_) << "\n";
00090 play_controller::init_gui();
00091
00092 if(first_human_team_ != -1) {
00093 gui_->scroll_to_tile(map_.starting_position(first_human_team_ + 1), game_display::WARP);
00094 }
00095 gui_->scroll_to_tile(map_.starting_position(1), game_display::WARP);
00096
00097 update_locker lock_display(gui_->video(),recorder.is_skipping());
00098 events::raise_draw_event();
00099 gui_->draw();
00100 }
00101
00102 void playsingle_controller::recruit(){
00103 if (!browse_)
00104 menu_handler_.recruit(player_number_, mouse_handler_.get_last_hex());
00105 else if (resources::whiteboard->is_active())
00106 menu_handler_.recruit(resources::screen->viewing_side(), mouse_handler_.get_last_hex());
00107 }
00108
00109 void playsingle_controller::repeat_recruit(){
00110 if (!browse_)
00111 menu_handler_.repeat_recruit(player_number_, mouse_handler_.get_last_hex());
00112 else if (resources::whiteboard->is_active())
00113 menu_handler_.repeat_recruit(resources::screen->viewing_side(), mouse_handler_.get_last_hex());
00114 }
00115
00116 void playsingle_controller::recall(){
00117 if (!browse_)
00118 menu_handler_.recall(player_number_, mouse_handler_.get_last_hex());
00119 else if (resources::whiteboard->is_active())
00120 menu_handler_.recall(resources::screen->viewing_side(), mouse_handler_.get_last_hex());
00121 }
00122
00123 void playsingle_controller::toggle_shroud_updates(){
00124 menu_handler_.toggle_shroud_updates(gui_->viewing_team()+1);
00125 }
00126
00127 void playsingle_controller::update_shroud_now(){
00128 menu_handler_.update_shroud_now(gui_->viewing_team()+1);
00129 }
00130
00131 void playsingle_controller::end_turn(){
00132 if (linger_)
00133 end_turn_ = true;
00134 else if (!browse_){
00135 browse_ = true;
00136 end_turn_ = menu_handler_.end_turn(player_number_);
00137 browse_ = end_turn_;
00138 }
00139 }
00140
00141 void playsingle_controller::force_end_turn(){
00142 skip_next_turn_ = true;
00143 end_turn_ = true;
00144 }
00145
00146 void playsingle_controller::check_end_level()
00147 {
00148 if (level_result_ == NONE || linger_)
00149 {
00150 team &t = teams_[gui_->viewing_team()];
00151 if (!browse_ && t.objectives_changed()) {
00152 dialogs::show_objectives(level_, t.objectives());
00153 t.reset_objectives_changed();
00154 }
00155 return;
00156 }
00157 throw end_level_exception(level_result_);
00158 }
00159
00160 void playsingle_controller::rename_unit(){
00161 menu_handler_.rename_unit();
00162 }
00163
00164 void playsingle_controller::create_unit(){
00165 menu_handler_.create_unit(mouse_handler_);
00166 }
00167
00168 void playsingle_controller::change_side(){
00169 menu_handler_.change_side(mouse_handler_);
00170 }
00171
00172 void playsingle_controller::label_terrain(bool team_only){
00173 menu_handler_.label_terrain(mouse_handler_, team_only);
00174 }
00175
00176 void playsingle_controller::clear_labels(){
00177 menu_handler_.clear_labels();
00178 }
00179
00180 void playsingle_controller::continue_move(){
00181 menu_handler_.continue_move(mouse_handler_, player_number_);
00182 }
00183
00184 void playsingle_controller::unit_hold_position(){
00185 if (!browse_)
00186 menu_handler_.unit_hold_position(mouse_handler_, player_number_);
00187 }
00188
00189 void playsingle_controller::end_unit_turn(){
00190 if (!browse_)
00191 menu_handler_.end_unit_turn(mouse_handler_, player_number_);
00192 }
00193
00194 void playsingle_controller::user_command(){
00195 menu_handler_.user_command();
00196 }
00197
00198 void playsingle_controller::custom_command(){
00199 menu_handler_.custom_command();
00200 }
00201
00202 void playsingle_controller::ai_formula(){
00203 menu_handler_.ai_formula();
00204 }
00205
00206 void playsingle_controller::clear_messages(){
00207 menu_handler_.clear_messages();
00208 }
00209
00210 void playsingle_controller::whiteboard_toggle() {
00211 resources::whiteboard->set_active(!resources::whiteboard->is_active());
00212
00213 resources::whiteboard->print_help_once();
00214 }
00215
00216 void playsingle_controller::whiteboard_execute_action(){
00217 whiteboard_manager_->contextual_execute();
00218 }
00219
00220 void playsingle_controller::whiteboard_execute_all_actions(){
00221 whiteboard_manager_->execute_all_actions();
00222 }
00223
00224 void playsingle_controller::whiteboard_delete_action(){
00225 whiteboard_manager_->contextual_delete();
00226 }
00227
00228 void playsingle_controller::whiteboard_bump_up_action()
00229 {
00230 whiteboard_manager_->contextual_bump_up_action();
00231 }
00232
00233 void playsingle_controller::whiteboard_bump_down_action()
00234 {
00235 whiteboard_manager_->contextual_bump_down_action();
00236 }
00237
00238 void playsingle_controller::whiteboard_suppose_dead()
00239 {
00240 unit* curr_unit;
00241 map_location loc;
00242 { wb::future_map future;
00243 curr_unit = &*menu_handler_.current_unit();
00244 loc = curr_unit->get_location();
00245 }
00246 whiteboard_manager_->save_suppose_dead(*curr_unit,loc);
00247 }
00248
00249 void playsingle_controller::report_victory(
00250 std::ostringstream &report, int player_gold, int remaining_gold,
00251 int finishing_bonus_per_turn, int turns_left, int finishing_bonus)
00252 {
00253 const end_level_data &end_level = get_end_level_data_const();
00254 report << _("Remaining gold: ")
00255 << utils::half_signed_value(remaining_gold) << "\n";
00256 if(end_level.gold_bonus) {
00257 if (turns_left > -1) {
00258 report << _("Early finish bonus: ")
00259 << finishing_bonus_per_turn
00260 << " " << _("per turn") << "\n"
00261 << "<b>" << _("Turns finished early: ")
00262 << turns_left << "</b>\n"
00263 << _("Bonus: ")
00264 << finishing_bonus << "\n";
00265 }
00266 report << _("Gold: ")
00267 << utils::half_signed_value(remaining_gold + finishing_bonus);
00268 }
00269 if (remaining_gold > 0) {
00270 report << '\n' << _("Carry over percentage: ") << end_level.carryover_percentage;
00271 }
00272 if(end_level.carryover_add) {
00273 report << "\n<b>" << _("Bonus Gold: ") << utils::half_signed_value(player_gold) <<"</b>";
00274 } else {
00275 report << "\n<b>" << _("Retained Gold: ") << utils::half_signed_value(player_gold) << "</b>";
00276 }
00277
00278 std::string goldmsg;
00279 utils::string_map symbols;
00280
00281 symbols["gold"] = lexical_cast_default<std::string>(player_gold);
00282
00283
00284
00285 if(end_level.carryover_add) {
00286 if(player_gold > 0) {
00287 goldmsg = vngettext(
00288 "You will start the next scenario with $gold "
00289 "on top of the defined minimum starting gold.",
00290 "You will start the next scenario with $gold "
00291 "on top of the defined minimum starting gold.",
00292 player_gold, symbols);
00293
00294 } else {
00295 goldmsg = vngettext(
00296 "You will start the next scenario with "
00297 "the defined minimum starting gold.",
00298 "You will start the next scenario with "
00299 "the defined minimum starting gold.",
00300 player_gold, symbols);
00301 }
00302 } else {
00303 goldmsg = vngettext(
00304 "You will start the next scenario with $gold "
00305 "or its defined minimum starting gold, "
00306 "whichever is higher.",
00307 "You will start the next scenario with $gold "
00308 "or its defined minimum starting gold, "
00309 "whichever is higher.",
00310 player_gold, symbols);
00311 }
00312
00313
00314 report << '\n' << goldmsg;
00315 }
00316
00317 LEVEL_RESULT playsingle_controller::play_scenario(
00318 const config::const_child_itors &story,
00319 bool skip_replay)
00320 {
00321 LOG_NG << "in playsingle_controller::play_scenario()...\n";
00322
00323
00324 foreach (const config &m, level_.child_range("music")) {
00325 sound::play_music_config(m);
00326 }
00327 sound::commit_music_changes();
00328
00329 if(!skip_replay) {
00330 show_story(*gui_, level_["name"], story);
00331 }
00332 gui_->labels().read(level_);
00333
00334
00335 assert(soundsources_manager_ != NULL);
00336 foreach (const config &s, level_.child_range("sound_source")) {
00337 soundsource::sourcespec spec(s);
00338 soundsources_manager_->add(spec);
00339 }
00340
00341 set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true));
00342 end_level_data &end_level = get_end_level_data();
00343 end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage);
00344 end_level.carryover_add = level_["carryover_add"].to_bool();
00345
00346 bool past_prestart = false;
00347
00348 LOG_NG << "entering try... " << (SDL_GetTicks() - ticks_) << "\n";
00349 try {
00350
00351 fire_prestart(!loading_game_);
00352 init_gui();
00353
00354 past_prestart = true;
00355
00356 LOG_NG << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n";
00357
00358 events::raise_draw_event();
00359 fire_start(!loading_game_);
00360 gui_->recalculate_minimap();
00361
00362 replaying_ = (recorder.at_end() == false);
00363
00364 LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";
00365
00366
00367 std::vector<team>::iterator t;
00368 for(t = teams_.begin(); t != teams_.end(); ++t) {
00369 if (gamestate_.mp_settings().mp_countdown && !loading_game_ ){
00370 t->set_countdown_time(1000 * gamestate_.mp_settings().mp_countdown_init_time);
00371 }
00372 }
00373
00374
00375 if (linger_) {
00376
00377 end_level.read(level_.child_or_empty("endlevel"));
00378 end_level.carryover_report = false;
00379 end_level.disabled = true;
00380 throw end_level_exception(SKIP_TO_LINGER);
00381 }
00382
00383
00384
00385 bool save = !loading_game_;
00386 ai_testing::log_game_start();
00387 for(; ; first_player_ = 1) {
00388 play_turn(save);
00389 save = true;
00390 }
00391
00392 #ifdef _MSC_VER
00393
00394 #pragma warning (push)
00395 #pragma warning (disable : 4101)
00396 #endif
00397 } catch(const game::load_game_exception& lge) {
00398
00399
00400 if (lge.game != "") {
00401 gamestate_ = game_state();
00402 }
00403 throw;
00404 } catch (end_level_exception &end_level_exn) {
00405 if(!past_prestart) {
00406 draw_solid_tinted_rectangle(
00407 0, 0, gui_->video().getx(), gui_->video().gety(), 0, 0, 0, 1.0,
00408 gui_->video().getSurface()
00409 );
00410 update_rect(0, 0, gui_->video().getx(), gui_->video().gety());
00411 }
00412
00413 ai_testing::log_game_end();
00414 LEVEL_RESULT end_level_result = end_level_exn.result;
00415 if (!end_level.custom_endlevel_music.empty()) {
00416 if (end_level_result == DEFEAT) {
00417 set_defeat_music_list(end_level.custom_endlevel_music);
00418 } else {
00419 set_victory_music_list(end_level.custom_endlevel_music);
00420 }
00421 }
00422
00423 if (teams_.empty())
00424 {
00425
00426 gamestate_.snapshot = config();
00427 store_recalls();
00428
00429 return VICTORY;
00430 }
00431 const bool obs = is_observer();
00432 if (game_config::exit_at_end) {
00433 exit(0);
00434 }
00435 if (end_level_result == DEFEAT || end_level_result == VICTORY)
00436 {
00437 gamestate_.classification().completion = (end_level_exn.result == VICTORY) ? "victory" : "defeat";
00438
00439
00440 if (!obs) {
00441 config cfg;
00442 config& info = cfg.add_child("info");
00443 info["type"] = "termination";
00444 info["condition"] = "game over";
00445 info["result"] = gamestate_.classification().completion;
00446 network::send_data(cfg, 0);
00447 } else {
00448 gui2::show_transient_message(gui_->video(),_("Game Over"),
00449 _("The game is over."));
00450 return OBSERVER_END;
00451 }
00452 }
00453
00454 if (end_level_result == QUIT) {
00455 return QUIT;
00456 }
00457 else if (end_level_result == DEFEAT)
00458 {
00459 gamestate_.classification().completion = "defeat";
00460 game_events::fire("defeat");
00461
00462 if (!obs) {
00463 const std::string& defeat_music = select_defeat_music();
00464 if(defeat_music.empty() != true)
00465 sound::play_music_once(defeat_music);
00466
00467 return DEFEAT;
00468 } else {
00469 return QUIT;
00470 }
00471 }
00472 else if (end_level_result == VICTORY)
00473 {
00474 gamestate_.classification().completion =
00475 !end_level.linger_mode ? "running" : "victory";
00476 game_events::fire("victory");
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487 if (!obs && end_level.linger_mode) {
00488 const std::string& victory_music = select_victory_music();
00489 if(victory_music.empty() != true)
00490 sound::play_music_once(victory_music);
00491 }
00492
00493
00494 LOG_NG << "Add units that survived the scenario to the recall list.\n";
00495 for(unit_map::iterator un = units_.begin(); un != units_.end(); ++un) {
00496
00497 if (teams_[un->side() - 1].persistent()) {
00498 LOG_NG << "Added unit " << un->id() << ", " << un->name() << "\n";
00499 un->new_turn();
00500 un->new_scenario();
00501 teams_[un->side() - 1].recall_list().push_back(*un);
00502 }
00503 }
00504
00505 gamestate_.snapshot = config();
00506 store_recalls();
00507
00508 store_gold(obs);
00509 return VICTORY;
00510 }
00511 else if (end_level_result == SKIP_TO_LINGER)
00512 {
00513 LOG_NG << "resuming from loaded linger state...\n";
00514
00515 gamestate_.snapshot = config();
00516 store_recalls();
00517 store_gold();
00518 return VICTORY;
00519 }
00520 }
00521 catch(network::error& e) {
00522 bool disconnect = false;
00523 if(e.socket) {
00524 e.disconnect();
00525 disconnect = true;
00526 }
00527
00528 savegame::game_savegame save(gamestate_, *gui_, to_config(), preferences::compress_saves());
00529 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);
00530 if(disconnect) {
00531 throw network::error();
00532 } else {
00533 return QUIT;
00534 }
00535 }
00536
00537 return QUIT;
00538 }
00539 #ifdef _MSC_VER
00540 #pragma warning (pop)
00541 #endif
00542
00543 void playsingle_controller::play_turn(bool save)
00544 {
00545 resources::whiteboard->on_gamestate_change();
00546 gui_->new_turn();
00547 gui_->invalidate_game_status();
00548 events::raise_draw_event();
00549
00550 LOG_NG << "turn: " << turn() << "\n";
00551
00552 if(non_interactive())
00553 std::cout << "Turn " << turn() << ":" << std::endl;
00554
00555
00556 for (player_number_ = first_player_; player_number_ <= int(teams_.size()); ++player_number_)
00557 {
00558
00559 if (current_team().is_empty()) continue;
00560 try {
00561 save_blocker blocker;
00562 init_side(player_number_ - 1);
00563 } catch (end_turn_exception) {
00564 if (current_team().is_network() == false) {
00565 turn_info turn_data(player_number_, replay_sender_);
00566 recorder.end_turn();
00567 turn_data.sync_network();
00568 }
00569 continue;
00570 }
00571
00572 if (replaying_) {
00573 LOG_NG << "doing replay " << player_number_ << "\n";
00574 replaying_ = ::do_replay(player_number_);
00575 LOG_NG << "result of replay: " << (replaying_?"true":"false") << "\n";
00576 } else {
00577
00578
00579 if (current_team().is_human() && side_units(player_number_) == 0
00580 && (resources::units->size() != 0 || player_number_ != 1))
00581 {
00582 turn_info turn_data(player_number_, replay_sender_);
00583 recorder.end_turn();
00584 turn_data.sync_network();
00585 continue;
00586 }
00587 ai_testing::log_turn_start(player_number_);
00588 play_side(player_number_, save);
00589 }
00590
00591 finish_side_turn();
00592
00593 if(non_interactive()) {
00594 std::cout << " Player " << player_number_ << ": " <<
00595 current_team().villages().size() << " Villages" <<
00596 std::endl;
00597 ai_testing::log_turn_end(player_number_);
00598 }
00599
00600 check_victory();
00601
00602
00603 loading_game_ = false;
00604 }
00605
00606
00607 if(player_number_ > static_cast<int>(teams_.size()))
00608 player_number_ = teams_.size();
00609
00610 finish_turn();
00611
00612
00613 check_time_over();
00614 }
00615
00616 void playsingle_controller::play_side(const unsigned int side_number, bool save)
00617 {
00618
00619 gui_->parse_team_overlays();
00620
00621
00622 bool temporary_human = false;
00623 do {
00624
00625
00626
00627 player_type_changed_ = false;
00628 if (!skip_next_turn_)
00629 end_turn_ = false;
00630
00631
00632 statistics::reset_turn_stats(teams_[side_number - 1].save_id());
00633
00634 if(current_team().is_human() || temporary_human) {
00635 LOG_NG << "is human...\n";
00636 try{
00637 before_human_turn(save);
00638 play_human_turn();
00639 after_human_turn();
00640 } catch(end_turn_exception& end_turn) {
00641 if (end_turn.redo == side_number) {
00642 player_type_changed_ = true;
00643
00644
00645 if (!teams_[side_number-1].is_human()) {
00646 browse_ = true;
00647 int t = find_human_team_before(side_number);
00648 if (t > 0) {
00649 update_gui_to_player(t-1);
00650 }
00651 }
00652 }
00653 }
00654
00655 LOG_NG << "human finished turn...\n";
00656 } else if(current_team().is_ai()) {
00657 try {
00658 play_ai_turn();
00659 } catch(fallback_ai_to_human_exception&) {
00660
00661 player_type_changed_ = true;
00662 temporary_human = true;
00663 }
00664 }
00665 } while (player_type_changed_);
00666
00667
00668 skip_next_turn_ = false;
00669 }
00670
00671 void playsingle_controller::before_human_turn(bool save)
00672 {
00673 log_scope("player turn");
00674 browse_ = false;
00675 linger_ = false;
00676
00677
00678 ai::manager::raise_turn_started();
00679
00680 if(save && level_result_ == NONE) {
00681 savegame::autosave_savegame save(gamestate_, *gui_, to_config(), preferences::compress_saves());
00682 save.autosave(game_config::disable_autosave, preferences::autosavemax(), preferences::INFINITE_AUTO_SAVES);
00683 }
00684
00685 if(preferences::turn_bell() && level_result_ == NONE) {
00686 sound::play_bell(game_config::sounds::turn_bell);
00687 }
00688 }
00689
00690 void playsingle_controller::show_turn_dialog(){
00691 if(preferences::turn_dialog() && (level_result_ == NONE) ) {
00692 std::string message = _("It is now $name|’s turn");
00693 utils::string_map symbols;
00694 symbols["name"] = teams_[player_number_ - 1].current_player();
00695 message = utils::interpolate_variables_into_string(message, &symbols);
00696 gui2::show_transient_message(gui_->video(), "", message);
00697 }
00698 }
00699
00700 void playsingle_controller::execute_gotos(){
00701 menu_handler_.execute_gotos(mouse_handler_, player_number_);
00702 }
00703
00704 void playsingle_controller::play_human_turn() {
00705 show_turn_dialog();
00706 execute_gotos();
00707
00708 gui_->enable_menu("endturn", true);
00709 while(!end_turn_) {
00710 play_slice();
00711 check_end_level();
00712 gui_->draw();
00713 }
00714 }
00715 struct set_completion
00716 {
00717 set_completion(game_state& state, const std::string& completion) :
00718 state_(state), completion_(completion)
00719 {
00720 }
00721 ~set_completion()
00722 {
00723 state_.classification().completion = completion_;
00724 }
00725 private:
00726 game_state& state_;
00727 const std::string completion_;
00728 };
00729
00730 void playsingle_controller::linger()
00731 {
00732 LOG_NG << "beginning end-of-scenario linger\n";
00733 browse_ = true;
00734 linger_ = true;
00735
00736
00737
00738 gui_->set_game_mode(game_display::LINGER_SP);
00739
00740
00741
00742
00743 set_completion setter(gamestate_,"running");
00744
00745
00746 gui_->get_theme().refresh_title2("button-endturn", "title2");
00747 gui_->invalidate_theme();
00748 gui_->redraw_everything();
00749
00750
00751 for (unit_map::iterator u = units_.begin(); u != units_.end(); ++u) {
00752 u->set_user_end_turn(true);
00753 }
00754 try {
00755
00756
00757 gui_->enable_menu("endturn", true);
00758 end_turn_ = false;
00759 while(!end_turn_) {
00760
00761 player_number_ = first_player_;
00762 play_slice();
00763 gui_->draw();
00764 }
00765 #ifdef _MSC_VER
00766 #pragma warning (push)
00767 #pragma warning (disable : 4101)
00768 #endif
00769 } catch(const game::load_game_exception& lge) {
00770
00771 if (lge.game != "") {
00772 gamestate_ = game_state();
00773 }
00774 throw;
00775 }
00776
00777
00778 gui_->get_theme().refresh_title2("button-endturn", "title");
00779 gui_->invalidate_theme();
00780 gui_->redraw_everything();
00781 gui_->set_game_mode(game_display::RUNNING);
00782
00783 LOG_NG << "ending end-of-scenario linger\n";
00784 }
00785 #ifdef _MSC_VER
00786 #pragma warning (pop)
00787 #endif
00788
00789 void playsingle_controller::end_turn_record()
00790 {
00791 if (!turn_over_)
00792 {
00793 turn_over_ = true;
00794 recorder.end_turn();
00795 }
00796 }
00797 void playsingle_controller::end_turn_record_unlock()
00798 {
00799 turn_over_ = false;
00800 }
00801
00802 hotkey::ACTION_STATE playsingle_controller::get_action_state(hotkey::HOTKEY_COMMAND command, int index) const
00803 {
00804 switch(command) {
00805 case hotkey::HOTKEY_WB_TOGGLE:
00806 return resources::whiteboard->is_active() ? hotkey::ACTION_ON : hotkey::ACTION_OFF;
00807 default:
00808 return play_controller::get_action_state(command, index);
00809 }
00810 }
00811
00812
00813
00814 void playsingle_controller::after_human_turn(){
00815 browse_ = true;
00816 end_turn_record();
00817 end_turn_record_unlock();
00818 menu_handler_.clear_undo_stack(player_number_);
00819
00820 if(teams_[player_number_-1].uses_fog()) {
00821
00822 recalculate_fog(player_number_);
00823 }
00824
00825 gui_->set_route(NULL);
00826 gui_->unhighlight_reach();
00827 }
00828
00829 void playsingle_controller::play_ai_turn(){
00830 LOG_NG << "is ai...\n";
00831 gui_->enable_menu("endturn", false);
00832 browse_ = true;
00833 gui_->recalculate_minimap();
00834
00835 const cursor::setter cursor_setter(cursor::WAIT);
00836
00837 turn_info turn_data(player_number_, replay_sender_);
00838
00839 try {
00840 ai::manager::play_turn(player_number_);
00841 } catch (end_turn_exception&) {
00842 }
00843 recorder.end_turn();
00844 turn_data.sync_network();
00845
00846 gui_->recalculate_minimap();
00847 recalculate_fog(player_number_);
00848 gui_->invalidate_unit();
00849 gui_->invalidate_game_status();
00850 gui_->invalidate_all();
00851 gui_->draw();
00852 gui_->delay(100);
00853 }
00854
00855 void playsingle_controller::handle_generic_event(const std::string& name){
00856 if (name == "ai_user_interact"){
00857 play_slice(false);
00858 }
00859 if (end_turn_){
00860 throw end_turn_exception();
00861 }
00862 }
00863
00864 void playsingle_controller::check_time_over(){
00865 bool b = tod_manager_.next_turn();
00866 it_is_a_new_turn_ = true;
00867 if(!b) {
00868
00869 LOG_NG << "firing time over event...\n";
00870 game_events::fire("time over");
00871 LOG_NG << "done firing time over event...\n";
00872
00873 if (tod_manager_.is_time_left()) {
00874 return;
00875 }
00876
00877 if(non_interactive()) {
00878 std::cout << "time over (draw)\n";
00879 ai_testing::log_draw();
00880 }
00881
00882 check_end_level();
00883 throw end_level_exception(DEFEAT);
00884 }
00885 }
00886
00887 void playsingle_controller::store_recalls() {
00888 std::set<std::string> side_ids;
00889 std::vector<team>::iterator i;
00890 for(i=teams_.begin(); i!=teams_.end(); ++i) {
00891 side_ids.insert(i->save_id());
00892 if (i->persistent()) {
00893 config& new_side = gamestate_.snapshot.add_child("side");
00894 new_side["save_id"] = i->save_id();
00895 new_side["name"] = i->current_player();
00896 std::stringstream can_recruit;
00897 std::copy(i->recruits().begin(),i->recruits().end(),std::ostream_iterator<std::string>(can_recruit,","));
00898 std::string can_recruit_str = can_recruit.str();
00899
00900 if(can_recruit_str.empty() == false) {
00901 can_recruit_str.resize(can_recruit_str.size()-1);
00902 }
00903 new_side["previous_recruits"] = can_recruit_str;
00904 LOG_NG << "stored side in snapshot:\n" << new_side["save_id"] << std::endl;
00905
00906 foreach(const unit& u, i->recall_list()) {
00907 config& new_unit = new_side.add_child("unit");
00908 u.write(new_unit);
00909 }
00910 }
00911 }
00912
00913 foreach (const config &player_cfg, gamestate_.starting_pos.child_range("player")) {
00914 if (side_ids.count(player_cfg["save_id"]) == 0) {
00915 LOG_NG << "stored inactive side in snapshot:\n" << player_cfg["save_id"] << std::endl;
00916 gamestate_.snapshot.add_child("side", player_cfg);
00917 }
00918 }
00919 }
00920
00921 void playsingle_controller::store_gold(bool obs)
00922 {
00923 bool has_next_scenario = !gamestate_.classification().next_scenario.empty() &&
00924 gamestate_.classification().next_scenario != "null";
00925
00926 std::ostringstream report;
00927 std::string title;
00928
00929 if (obs) {
00930 title = _("Scenario Report");
00931 } else {
00932 persist_.end_transaction();
00933 title = _("Victory");
00934 report << "<b>" << _("You have emerged victorious!") << "</b>\n\n";
00935 }
00936
00937 int persistent_teams = 0;
00938 foreach (const team &t, teams_) {
00939 if (t.persistent()) ++persistent_teams;
00940 }
00941
00942 const end_level_data &end_level = get_end_level_data_const();
00943
00944 if (persistent_teams > 0 && (has_next_scenario ||
00945 gamestate_.classification().campaign_type == "test"))
00946 {
00947 int finishing_bonus_per_turn =
00948 map_.villages().size() * game_config::village_income +
00949 game_config::base_income;
00950 int turns_left = std::max<int>(0, tod_manager_.number_of_turns() - turn());
00951 int finishing_bonus = (end_level.gold_bonus && turns_left > -1) ?
00952 finishing_bonus_per_turn * turns_left : 0;
00953 foreach (const team &t, teams_)
00954 {
00955 if (!t.persistent()) continue;
00956 int carryover_gold = div100rounded((t.gold() + finishing_bonus) * end_level.carryover_percentage);
00957 config::child_itors side_range = gamestate_.snapshot.child_range("side");
00958 config::child_iterator side_it = side_range.first;
00959
00960
00961 while (side_it != side_range.second) {
00962 if ((*side_it)["save_id"] == t.save_id()) {
00963 (*side_it)["gold"] = str_cast<int>(carryover_gold);
00964 (*side_it)["gold_add"] = end_level.carryover_add;
00965 (*side_it)["color"] = t.color();
00966 (*side_it)["current_player"] = t.current_player();
00967 (*side_it)["name"] = t.name();
00968 break;
00969 }
00970 ++side_it;
00971 }
00972
00973
00974 if (side_it == side_range.second) {
00975 config &new_side = gamestate_.snapshot.add_child("side");
00976 new_side["save_id"] = t.save_id();
00977 new_side["gold"] = str_cast<int>(carryover_gold);
00978 new_side["gold_add"] = end_level.carryover_add;
00979 new_side["color"] = t.color();
00980 new_side["current_player"] = t.current_player();
00981 new_side["name"] = t.name();
00982 }
00983
00984
00985 if (!t.is_human()) continue;
00986
00987 if (persistent_teams > 1) {
00988 report << "\n<b>" << t.current_player() << "</b>\n";
00989 }
00990
00991 report_victory(report, carryover_gold, t.gold(), finishing_bonus_per_turn, turns_left, finishing_bonus);
00992 }
00993 }
00994
00995 if (end_level.carryover_report) {
00996 gui2::show_transient_message(gui_->video(), title, report.str(), "", true);
00997 }
00998 }
00999
01000 bool playsingle_controller::can_execute_command(hotkey::HOTKEY_COMMAND command, int index) const
01001 {
01002 bool res = true;
01003 switch (command){
01004 case hotkey::HOTKEY_UNIT_HOLD_POSITION:
01005 case hotkey::HOTKEY_END_UNIT_TURN:
01006 return !browse_ && !linger_ && !events::commands_disabled;
01007 case hotkey::HOTKEY_RECRUIT:
01008 case hotkey::HOTKEY_REPEAT_RECRUIT:
01009 case hotkey::HOTKEY_RECALL:
01010 return (!browse_ || resources::whiteboard->is_active()) && !linger_ && !events::commands_disabled;
01011 case hotkey::HOTKEY_ENDTURN:
01012 return (!browse_ || linger_) && !events::commands_disabled;
01013
01014 case hotkey::HOTKEY_DELAY_SHROUD:
01015 return !linger_ && (teams_[gui_->viewing_team()].uses_fog() || teams_[gui_->viewing_team()].uses_shroud())
01016 && !events::commands_disabled;
01017 case hotkey::HOTKEY_UPDATE_SHROUD:
01018 return !linger_
01019 && player_number_ == gui_->viewing_side()
01020 && !events::commands_disabled
01021 && teams_[gui_->viewing_team()].auto_shroud_updates() == false;
01022
01023
01024 case hotkey::HOTKEY_CREATE_UNIT:
01025 case hotkey::HOTKEY_CHANGE_SIDE:
01026 return !events::commands_disabled && game_config::debug && map_.on_board(mouse_handler_.get_last_hex());
01027
01028 case hotkey::HOTKEY_CLEAR_LABELS:
01029 res = !is_observer();
01030 break;
01031 case hotkey::HOTKEY_LABEL_TEAM_TERRAIN:
01032 case hotkey::HOTKEY_LABEL_TERRAIN: {
01033 const terrain_label *label = resources::screen->labels().get_label(mouse_handler_.get_last_hex());
01034 res = !events::commands_disabled && map_.on_board(mouse_handler_.get_last_hex())
01035 && !gui_->shrouded(mouse_handler_.get_last_hex())
01036 && !is_observer()
01037 && (!label || !label->immutable());
01038 break;
01039 }
01040 case hotkey::HOTKEY_CONTINUE_MOVE: {
01041 if(browse_ || events::commands_disabled)
01042 return false;
01043
01044 if( (menu_handler_.current_unit() != units_.end())
01045 && (menu_handler_.current_unit()->move_interrupted()))
01046 return true;
01047 const unit_map::const_iterator i = units_.find(mouse_handler_.get_selected_hex());
01048 if (i == units_.end()) return false;
01049 return i->move_interrupted();
01050 }
01051 case hotkey::HOTKEY_WB_TOGGLE:
01052 return true;
01053 case hotkey::HOTKEY_WB_EXECUTE_ACTION:
01054 case hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS:
01055 return resources::whiteboard->can_enable_execution_hotkeys();
01056 case hotkey::HOTKEY_WB_DELETE_ACTION:
01057 return resources::whiteboard->can_enable_modifier_hotkeys();
01058 case hotkey::HOTKEY_WB_BUMP_UP_ACTION:
01059 case hotkey::HOTKEY_WB_BUMP_DOWN_ACTION:
01060 return resources::whiteboard->can_enable_reorder_hotkeys();
01061 case hotkey::HOTKEY_WB_SUPPOSE_DEAD:
01062 {
01063
01064 return false;
01065 }
01066
01067 default: return play_controller::can_execute_command(command, index);
01068 }
01069 return res;
01070 }