00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "play_controller.hpp"
00020 #include "dialogs.hpp"
00021 #include "config_adapter.hpp"
00022 #include "game_display.hpp"
00023 #include "game_errors.hpp"
00024 #include "gettext.hpp"
00025 #include "loadscreen.hpp"
00026 #include "log.hpp"
00027 #include "sound.hpp"
00028 #include "team.hpp"
00029 #include "terrain_filter.hpp"
00030 #include "variable.hpp"
00031
00032 #include <cassert>
00033
00034 #define LOG_NG LOG_STREAM(info, engine)
00035
00036 play_controller::play_controller(const config& level,
00037 game_state& state_of_game, int ticks, int num_turns, const config& game_config,
00038 CVideo& video, bool skip_replay, bool is_replay) :
00039 verify_manager_(units_), team_manager_(teams_), labels_manager_(),
00040 help_manager_(&game_config, &map_), mouse_handler_(gui_, teams_,
00041 units_, map_, status_, undo_stack_, redo_stack_),
00042 menu_handler_(gui_, units_, teams_, level, map_, game_config,
00043 status_, state_of_game, undo_stack_, redo_stack_),
00044 generator_setter(&recorder), statistics_context_(level["name"]),
00045 level_(level), game_config_(game_config),
00046 gamestate_(state_of_game), status_(level, num_turns, &state_of_game),
00047 map_(game_config, level["map_data"]), ticks_(ticks),
00048 xp_mod_(atoi(level["experience_modifier"].c_str()) > 0 ? atoi(level["experience_modifier"].c_str()) : 100),
00049 loading_game_(level["playing_team"].empty() == false),
00050 first_human_team_(-1), player_number_(1),
00051 first_player_ (lexical_cast_default<unsigned int,std::string>(level_["playing_team"], 0) + 1),
00052 start_turn_(status_.turn()), is_host_(true), skip_replay_(skip_replay),
00053 browse_(false), linger_(false), scrolling_(false)
00054 {
00055 status_.teams = &teams_;
00056 game_config::add_color_info(level);
00057
00058 init(video, is_replay);
00059 }
00060
00061 play_controller::~play_controller(){
00062 delete halo_manager_;
00063 delete prefs_disp_manager_;
00064 delete tooltips_manager_;
00065 delete events_manager_;
00066 delete soundsources_manager_;
00067 delete gui_;
00068 }
00069
00070 void play_controller::init(CVideo& video, bool is_replay){
00071 loadscreen::global_loadscreen_manager loadscreen_manager(video);
00072
00073
00074
00075 if(recorder.empty()) {
00076 recorder.add_start();
00077 } else {
00078 recorder.pre_replay();
00079 }
00080 recorder.set_skip(false);
00081
00082 const config::child_list& unit_cfg = level_.get_children("side");
00083 const bool snapshot = utils::string_bool(level_["snapshot"]);
00084
00085 if(utils::string_bool(level_["modify_placing"])) {
00086 LOG_NG << "modifying placing...\n";
00087 place_sides_in_preferred_locations(map_,unit_cfg);
00088 }
00089
00090 loadscreen::global_loadscreen->set_progress(70, _("Initializing teams"));
00091
00092 LOG_NG << "initializing teams..." << unit_cfg.size() << "\n";;
00093 LOG_NG << (SDL_GetTicks() - ticks_) << "\n";
00094
00095 std::set<std::string> seen_save_ids;
00096
00097 for(config::child_list::const_iterator ui = unit_cfg.begin(); ui != unit_cfg.end(); ++ui) {
00098 std::string save_id = get_unique_saveid(**ui, seen_save_ids);
00099 seen_save_ids.insert(save_id);
00100 if (first_human_team_ == -1){
00101 first_human_team_ = get_first_human_team(ui, unit_cfg);
00102 }
00103 get_player_info(**ui, gamestate_, save_id, teams_, level_, map_, units_, status_, snapshot, is_replay );
00104 }
00105
00106 loadscreen::global_loadscreen->set_progress(80, _("Initializing display"));
00107
00108 preferences::encounter_recruitable_units(teams_);
00109 preferences::encounter_start_units(units_);
00110 preferences::encounter_recallable_units(gamestate_);
00111 preferences::encounter_map_terrain(map_);
00112
00113 LOG_NG << "initialized teams... " << (SDL_GetTicks() - ticks_) << "\n";
00114 LOG_NG << "initializing display... " << (SDL_GetTicks() - ticks_) << "\n";
00115
00116 const config* theme_cfg = get_theme(game_config_, level_["theme"]);
00117 if (theme_cfg)
00118 gui_ = new game_display(units_,video,map_,status_,teams_,*theme_cfg, game_config_, level_);
00119 else
00120 gui_ = new game_display(units_,video,map_,status_,teams_,config(), game_config_, level_);
00121 loadscreen::global_loadscreen->set_progress(90, _("Initializing display"));
00122 mouse_handler_.set_gui(gui_);
00123 menu_handler_.set_gui(gui_);
00124 theme::set_known_themes(&game_config_);
00125
00126 LOG_NG << "done initializing display... " << (SDL_GetTicks() - ticks_) << "\n";
00127
00128 if(first_human_team_ != -1) {
00129 gui_->set_team(first_human_team_);
00130 }
00131 else if (team_manager_.is_observer())
00132 {
00133
00134
00135
00136 size_t i;
00137 for (i=0;i < teams_.size();++i)
00138 {
00139 if (!teams_[i].get_disallow_observers())
00140 {
00141 gui_->set_team(i);
00142 }
00143 }
00144 }
00145
00146 init_managers();
00147 loadscreen::global_loadscreen->set_progress(100, _("Starting game"));
00148 loadscreen::global_loadscreen = NULL;
00149 }
00150
00151 void play_controller::init_managers(){
00152 LOG_NG << "initializing managers... " << (SDL_GetTicks() - ticks_) << "\n";
00153 prefs_disp_manager_ = new preferences::display_manager(gui_);
00154 tooltips_manager_ = new tooltips::manager(gui_->video());
00155 soundsources_manager_ = new soundsource::manager(*gui_);
00156
00157
00158
00159 events_manager_ = new game_events::manager(level_,*gui_,map_, *soundsources_manager_,
00160 units_,teams_, gamestate_,status_);
00161
00162 halo_manager_ = new halo::manager(*gui_);
00163 LOG_NG << "done initializing managers... " << (SDL_GetTicks() - ticks_) << "\n";
00164 }
00165
00166 static int placing_score(const config& side, const gamemap& map, const gamemap::location& pos)
00167 {
00168 int positions = 0, liked = 0;
00169 const t_translation::t_list terrain = t_translation::read_list(side["terrain_liked"]);
00170
00171 for(int i = pos.x-8; i != pos.x+8; ++i) {
00172 for(int j = pos.y-8; j != pos.y+8; ++j) {
00173 const gamemap::location pos(i,j);
00174 if(map.on_board(pos)) {
00175 ++positions;
00176 if(std::count(terrain.begin(),terrain.end(),map[pos])) {
00177 ++liked;
00178 }
00179 }
00180 }
00181 }
00182
00183 return (100*liked)/positions;
00184 }
00185
00186 struct placing_info {
00187 int side, score;
00188 gamemap::location pos;
00189 };
00190
00191 static bool operator<(const placing_info& a, const placing_info& b) { return a.score > b.score; }
00192
00193 void play_controller::place_sides_in_preferred_locations(gamemap& map, const config::child_list& sides)
00194 {
00195 std::vector<placing_info> placings;
00196
00197 const int num_pos = map.num_valid_starting_positions();
00198
00199 for(config::child_list::const_iterator s = sides.begin(); s != sides.end(); ++s) {
00200 const int side_num = s - sides.begin() + 1;
00201 for(int p = 1; p <= num_pos; ++p) {
00202 const gamemap::location& pos = map.starting_position(p);
00203 const int score = placing_score(**s,map,pos);
00204 placing_info obj;
00205 obj.side = side_num;
00206 obj.score = score;
00207 obj.pos = pos;
00208 placings.push_back(obj);
00209 }
00210 }
00211
00212 std::sort(placings.begin(),placings.end());
00213 std::set<int> placed;
00214 std::set<gamemap::location> positions_taken;
00215
00216 for(std::vector<placing_info>::const_iterator i = placings.begin(); i != placings.end() && placed.size() != sides.size(); ++i) {
00217 if(placed.count(i->side) == 0 && positions_taken.count(i->pos) == 0) {
00218 placed.insert(i->side);
00219 positions_taken.insert(i->pos);
00220 map.set_starting_position(i->side,i->pos);
00221 LOG_NG << "placing side " << i->side << " at " << i->pos << '\n';
00222 }
00223 }
00224 }
00225
00226 void play_controller::objectives(){
00227 menu_handler_.objectives(player_number_);
00228 }
00229
00230 void play_controller::show_statistics(){
00231 menu_handler_.show_statistics(gui_->viewing_team()+1);
00232 }
00233
00234 void play_controller::unit_list(){
00235 menu_handler_.unit_list();
00236 }
00237
00238 void play_controller::status_table(){
00239 menu_handler_.status_table();
00240 }
00241
00242 void play_controller::save_game(){
00243 menu_handler_.save_game("",gui::OK_CANCEL);
00244 }
00245
00246 void play_controller::save_replay(){
00247 menu_handler_.save_game("", gui::OK_CANCEL, false, true);
00248 }
00249
00250 void play_controller::save_map(){
00251 menu_handler_.save_map();
00252 }
00253
00254 void play_controller::load_game(){
00255 menu_handler_.load_game();
00256 }
00257
00258 void play_controller::preferences(){
00259 menu_handler_.preferences();
00260 }
00261
00262 void play_controller::cycle_units(){
00263 mouse_handler_.cycle_units(browse_);
00264 }
00265
00266 void play_controller::cycle_back_units(){
00267 mouse_handler_.cycle_back_units(browse_);
00268 }
00269
00270 void play_controller::show_chat_log(){
00271 menu_handler_.show_chat_log();
00272 }
00273
00274 void play_controller::show_help(){
00275 menu_handler_.show_help();
00276 }
00277
00278 void play_controller::undo(){
00279
00280 mouse_handler_.deselect_hex();
00281 menu_handler_.undo(player_number_);
00282 }
00283
00284 void play_controller::redo(){
00285
00286 mouse_handler_.deselect_hex();
00287 menu_handler_.redo(player_number_);
00288 }
00289
00290 void play_controller::show_enemy_moves(bool ignore_units){
00291 menu_handler_.show_enemy_moves(ignore_units, player_number_);
00292 }
00293
00294 void play_controller::goto_leader(){
00295 menu_handler_.goto_leader(player_number_);
00296 }
00297
00298 void play_controller::unit_description(){
00299 menu_handler_.unit_description(mouse_handler_);
00300 }
00301
00302 void play_controller::toggle_grid(){
00303 menu_handler_.toggle_grid();
00304 }
00305
00306 void play_controller::search(){
00307 menu_handler_.search();
00308 }
00309
00310 int play_controller::get_ticks(){
00311 return ticks_;
00312 }
00313
00314 void play_controller::fire_prestart(bool execute){
00315
00316
00317 if (execute){
00318 update_locker lock_display(gui_->video());
00319 game_events::fire("prestart");
00320 }
00321 }
00322
00323 void play_controller::fire_start(bool execute){
00324 if(execute) {
00325 game_events::fire("start");
00326 gamestate_.set_variable("turn_number", "1");
00327 first_turn_ = true;
00328 } else {
00329 first_turn_ = false;
00330 }
00331 }
00332
00333 void play_controller::init_gui(){
00334 gui_->begin_game();
00335 gui_->adjust_colours(0,0,0);
00336
00337 for(std::vector<team>::iterator t = teams_.begin(); t != teams_.end(); ++t) {
00338 ::clear_shroud(*gui_,map_,units_,teams_,(t-teams_.begin()));
00339 }
00340 }
00341
00342 void play_controller::init_side(const unsigned int team_index, bool ){
00343 log_scope("player turn");
00344 team& current_team = teams_[team_index];
00345
00346 mouse_handler_.set_team(team_index+1);
00347
00348
00349 if (team_manager_.is_observer()
00350 && !current_team.get_disallow_observers()) {
00351 gui_->set_team(size_t(team_index));
00352 }
00353 gui_->set_playing_team(size_t(team_index));
00354
00355 std::stringstream player_number_str;
00356 player_number_str << player_number_;
00357 gamestate_.set_variable("side_number",player_number_str.str());
00358 gamestate_.last_selected = gamemap::location::null_location;
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368 bool real_side_change = true;
00369 if(first_turn_) {
00370 game_events::fire("turn 1");
00371 game_events::fire("new turn");
00372 game_events::fire("side turn");
00373 first_turn_ = false;
00374 } else if (team_index != (first_player_ - 1) || status_.turn() > start_turn_) {
00375
00376
00377 game_events::fire("side turn");
00378 } else {
00379 real_side_change = false;
00380 }
00381
00382
00383
00384
00385
00386 const bool turn_refresh = status_.turn() > start_turn_ || (loading_game_ && team_index != (first_player_ - 1));
00387
00388 if(turn_refresh) {
00389 for(unit_map::iterator i = units_.begin(); i != units_.end(); ++i) {
00390 if(i->second.side() == static_cast<size_t>(player_number_)) {
00391 i->second.new_turn();
00392 }
00393 }
00394
00395 current_team.new_turn();
00396
00397
00398
00399 const int expense = team_upkeep(units_,player_number_) -
00400 current_team.villages().size();
00401 if(expense > 0) {
00402 current_team.spend_gold(expense);
00403 }
00404
00405 calculate_healing((*gui_),map_,units_,player_number_,teams_, !skip_replay_);
00406 reset_resting(units_, player_number_);
00407 }
00408 if(turn_refresh || real_side_change) {
00409 game_events::fire("turn refresh");
00410 }
00411
00412 const time_of_day &tod = status_.get_time_of_day();
00413 current_team.set_time_of_day(int(status_.turn()), tod);
00414
00415 if(team_index == first_player_ - 1)
00416 sound::play_sound(tod.sounds, sound::SOUND_SOURCES);
00417
00418 if (!recorder.is_skipping()){
00419 ::clear_shroud(*gui_,map_,units_,teams_,team_index);
00420 gui_->invalidate_all();
00421 }
00422
00423 if (!recorder.is_skipping() && !skip_replay_){
00424 gui_->scroll_to_leader(units_, player_number_);
00425 }
00426 }
00427
00428 void play_controller::finish_side_turn(){
00429 for(unit_map::iterator uit = units_.begin(); uit != units_.end(); ++uit) {
00430 if(uit->second.side() == player_number_)
00431 uit->second.end_turn();
00432 }
00433
00434
00435
00436 if(current_team().copy_ally_shroud()) {
00437 gui_->recalculate_minimap();
00438 gui_->invalidate_all();
00439 }
00440
00441 mouse_handler_.deselect_hex();
00442 game_events::pump();
00443 }
00444
00445 void play_controller::finish_turn(){
00446 std::stringstream event_stream;
00447 event_stream << status_.turn();
00448
00449 {
00450 LOG_NG << "turn event..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n";
00451 update_locker lock_display(gui_->video(),recorder.is_skipping());
00452 const std::string turn_num = event_stream.str();
00453 gamestate_.set_variable("turn_number",turn_num);
00454 game_events::fire("turn " + turn_num);
00455 game_events::fire("new turn");
00456 }
00457 }
00458
00459 bool play_controller::enemies_visible() const
00460 {
00461
00462 if(current_team().uses_fog() == false && current_team().uses_shroud() == false)
00463 return true;
00464
00465
00466 for(unit_map::const_iterator u = units_.begin(); u != units_.end(); ++u)
00467 if(current_team().is_enemy(u->second.side()) && !gui_->fogged(u->first))
00468 return true;
00469
00470 return false;
00471 }
00472
00473 bool play_controller::execute_command(hotkey::HOTKEY_COMMAND command, int index)
00474 {
00475 if(index >= 0) {
00476 unsigned i = static_cast<unsigned>(index);
00477 if(i < savenames_.size() && !savenames_[i].empty()) {
00478
00479 throw game::load_game_exception(savenames_[i],false,false);
00480
00481 } else if (i < wml_commands_.size() && wml_commands_[i] != NULL) {
00482 if(gamestate_.last_selected.valid() && wml_commands_[i]->needs_select) {
00483 recorder.add_event("select", gamestate_.last_selected);
00484 }
00485 gamemap::location const& menu_hex = mouse_handler_.get_last_hex();
00486 recorder.add_event(wml_commands_[i]->name, menu_hex);
00487 if(game_events::fire(wml_commands_[i]->name, menu_hex)) {
00488
00489 apply_shroud_changes(undo_stack_, gui_, map_,
00490 units_, teams_, (player_number_ - 1));
00491 undo_stack_.clear();
00492 }
00493 return true;
00494 }
00495 }
00496 return command_executor::execute_command(command, index);
00497 }
00498
00499
00500 bool play_controller::can_execute_command(hotkey::HOTKEY_COMMAND command, int index) const
00501 {
00502 if(index >= 0) {
00503 unsigned i = static_cast<unsigned>(index);
00504 if((i < savenames_.size() && !savenames_[i].empty())
00505 || (i < wml_commands_.size() && wml_commands_[i] != NULL)) {
00506 return true;
00507 }
00508 }
00509 switch(command) {
00510
00511
00512 case hotkey::HOTKEY_LEADER:
00513 case hotkey::HOTKEY_CYCLE_UNITS:
00514 case hotkey::HOTKEY_CYCLE_BACK_UNITS:
00515 case hotkey::HOTKEY_ZOOM_IN:
00516 case hotkey::HOTKEY_ZOOM_OUT:
00517 case hotkey::HOTKEY_ZOOM_DEFAULT:
00518 case hotkey::HOTKEY_FULLSCREEN:
00519 case hotkey::HOTKEY_SCREENSHOT:
00520 case hotkey::HOTKEY_MAP_SCREENSHOT:
00521 case hotkey::HOTKEY_ACCELERATED:
00522 case hotkey::HOTKEY_SAVE_MAP:
00523 case hotkey::HOTKEY_TOGGLE_GRID:
00524 case hotkey::HOTKEY_MOUSE_SCROLL:
00525 case hotkey::HOTKEY_STATUS_TABLE:
00526 case hotkey::HOTKEY_MUTE:
00527 case hotkey::HOTKEY_PREFERENCES:
00528 case hotkey::HOTKEY_OBJECTIVES:
00529 case hotkey::HOTKEY_UNIT_LIST:
00530 case hotkey::HOTKEY_STATISTICS:
00531 case hotkey::HOTKEY_QUIT_GAME:
00532 case hotkey::HOTKEY_SEARCH:
00533 case hotkey::HOTKEY_HELP:
00534 case hotkey::HOTKEY_USER_CMD:
00535 case hotkey::HOTKEY_CUSTOM_CMD:
00536 case hotkey::HOTKEY_AI_FORMULA:
00537 case hotkey::HOTKEY_CLEAR_MSG:
00538 #ifdef USRCMD2
00539
00540 case hotkey::HOTKEY_USER_CMD_2:
00541 case hotkey::HOTKEY_USER_CMD_3:
00542 #endif
00543 return true;
00544
00545
00546 case hotkey::HOTKEY_SAVE_GAME:
00547 case hotkey::HOTKEY_SAVE_REPLAY:
00548 return !events::commands_disabled;
00549
00550 case hotkey::HOTKEY_SHOW_ENEMY_MOVES:
00551 case hotkey::HOTKEY_BEST_ENEMY_MOVES:
00552 return !linger_ && enemies_visible();
00553
00554 case hotkey::HOTKEY_LOAD_GAME:
00555 return network::nconnections() == 0;
00556
00557 case hotkey::HOTKEY_CHAT_LOG:
00558 return network::nconnections() > 0;
00559
00560 case hotkey::HOTKEY_REDO:
00561 return !linger_ && !redo_stack_.empty() && !events::commands_disabled;
00562 case hotkey::HOTKEY_UNDO:
00563 return !linger_ && !undo_stack_.empty() && !events::commands_disabled;
00564
00565 case hotkey::HOTKEY_UNIT_DESCRIPTION:
00566 return menu_handler_.current_unit(mouse_handler_) != units_.end();
00567
00568 case hotkey::HOTKEY_RENAME_UNIT:
00569 return !events::commands_disabled &&
00570 menu_handler_.current_unit(mouse_handler_) != units_.end() &&
00571 !(menu_handler_.current_unit(mouse_handler_)->second.unrenamable()) &&
00572 menu_handler_.current_unit(mouse_handler_)->second.side() == gui_->viewing_team()+1 &&
00573 teams_[menu_handler_.current_unit(mouse_handler_)->second.side() - 1].is_human();
00574
00575 default:
00576 return false;
00577 }
00578 }
00579
00580 void play_controller::enter_textbox()
00581 {
00582 if(menu_handler_.get_textbox().active() == false) {
00583 return;
00584 }
00585
00586 const std::string str = menu_handler_.get_textbox().box()->text();
00587 const unsigned int team_num = player_number_;
00588 events::mouse_handler& mousehandler = mouse_handler_;
00589
00590 switch(menu_handler_.get_textbox().mode()) {
00591 case gui::TEXTBOX_SEARCH:
00592 menu_handler_.do_search(str);
00593 menu_handler_.get_textbox().close(*gui_);
00594 break;
00595 case gui::TEXTBOX_MESSAGE:
00596 menu_handler_.do_speak();
00597 menu_handler_.get_textbox().close(*gui_);
00598 break;
00599 case gui::TEXTBOX_COMMAND:
00600 menu_handler_.get_textbox().close(*gui_);
00601 menu_handler_.do_command(str, team_num, mousehandler);
00602 break;
00603 case gui::TEXTBOX_AI:
00604 menu_handler_.get_textbox().close(*gui_);
00605 menu_handler_.do_ai_formula(str, team_num, mousehandler);
00606 break;
00607 default:
00608 menu_handler_.get_textbox().close(*gui_);
00609 LOG_STREAM(err, display) << "unknown textbox mode\n";
00610 }
00611
00612 }
00613
00614 team& play_controller::current_team()
00615 {
00616 assert(player_number_ > 0 && player_number_ <= teams_.size());
00617 return teams_[player_number_-1];
00618 }
00619
00620 const team& play_controller::current_team() const
00621 {
00622 assert(player_number_ > 0 && player_number_ <= teams_.size());
00623 return teams_[player_number_-1];
00624 }
00625
00626
00627 int play_controller::find_human_team_before(const size_t team_num) const
00628 {
00629 if (team_num > teams_.size())
00630 return -2;
00631
00632 int human_side = -2;
00633 for (int i = team_num-2; i > -1; --i) {
00634 if (teams_[i].is_human()) {
00635 human_side = i;
00636 break;
00637 }
00638 }
00639 if (human_side == -2) {
00640 for (size_t i = teams_.size()-1; i > team_num-1; --i) {
00641 if (teams_[i].is_human()) {
00642 human_side = i;
00643 break;
00644 }
00645 }
00646 }
00647 return human_side+1;
00648 }
00649
00650
00651 void play_controller::handle_event(const SDL_Event& event)
00652 {
00653 if(gui::in_dialog()) {
00654 return;
00655 }
00656
00657 switch(event.type) {
00658 case SDL_KEYDOWN:
00659
00660
00661
00662 if(menu_handler_.get_textbox().active() == false) {
00663 hotkey::key_event(*gui_,event.key,this);
00664 } else {
00665 if(event.key.keysym.sym == SDLK_ESCAPE) {
00666 menu_handler_.get_textbox().close(*gui_);
00667 } else if(event.key.keysym.sym == SDLK_TAB) {
00668 menu_handler_.get_textbox().tab(teams_, units_, *gui_);
00669 } else if(event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER) {
00670 enter_textbox();
00671 }
00672 break;
00673 }
00674
00675
00676 case SDL_KEYUP:
00677
00678
00679
00680 if(event.key.keysym.sym >= '1' && event.key.keysym.sym <= '7') {
00681 const int new_path_turns = (event.type == SDL_KEYDOWN) ?
00682 event.key.keysym.sym - '1' : 0;
00683
00684 if(new_path_turns != mouse_handler_.get_path_turns()) {
00685 mouse_handler_.set_path_turns(new_path_turns);
00686
00687 const unit_map::iterator u = mouse_handler_.selected_unit();
00688
00689 if(u != units_.end()) {
00690 const bool teleport = u->second.get_ability_bool("teleport",u->first);
00691 mouse_handler_.set_current_paths(paths(map_,units_,u->first,
00692 teams_,false,teleport, teams_[gui_->viewing_team()],
00693 mouse_handler_.get_path_turns()));
00694 gui_->highlight_reach(mouse_handler_.get_current_paths());
00695 }
00696 }
00697 }
00698
00699
00700
00701
00702 break;
00703 case SDL_MOUSEMOTION:
00704
00705 SDL_Event new_event;
00706
00707 if(SDL_PeepEvents(&new_event,1,SDL_GETEVENT,
00708 SDL_EVENTMASK(SDL_MOUSEMOTION)) > 0) {
00709 while(SDL_PeepEvents(&new_event,1,SDL_GETEVENT,
00710 SDL_EVENTMASK(SDL_MOUSEMOTION)) > 0) {};
00711 mouse_handler_.mouse_motion(new_event.motion, browse_);
00712 } else {
00713 mouse_handler_.mouse_motion(event.motion, browse_);
00714 }
00715 break;
00716 case SDL_MOUSEBUTTONDOWN:
00717 case SDL_MOUSEBUTTONUP:
00718 mouse_handler_.mouse_press(event.button, browse_);
00719 if (mouse_handler_.get_undo()){
00720 mouse_handler_.set_undo(false);
00721 menu_handler_.undo(player_number_);
00722 }
00723 if (mouse_handler_.get_show_menu()){
00724 show_menu(gui_->get_theme().context_menu()->items(),event.button.x,event.button.y,true);
00725 }
00726 break;
00727 default:
00728 break;
00729 }
00730 }
00731
00732 void play_controller::play_slice()
00733 {
00734 CKey key;
00735
00736 events::pump();
00737 events::raise_process_event();
00738
00739 events::raise_draw_event();
00740 soundsources_manager_->update();
00741
00742 const theme::menu* const m = gui_->menu_pressed();
00743 if(m != NULL) {
00744 const SDL_Rect& menu_loc = m->location(gui_->screen_area());
00745 show_menu(m->items(),menu_loc.x+1,menu_loc.y + menu_loc.h + 1,false);
00746 return;
00747 }
00748
00749 int mousex, mousey;
00750 bool middle_pressed = (SDL_GetMouseState(&mousex,&mousey)& SDL_BUTTON(2)) != 0;
00751 tooltips::process(mousex, mousey);
00752
00753 const int scroll_threshold = (preferences::mouse_scroll_enabled()) ? 5 : 0;
00754 bool was_scrolling = scrolling_;
00755 scrolling_ = false;
00756
00757 if((key[SDLK_UP] && !menu_handler_.get_textbox().active()) || mousey < scroll_threshold) {
00758 gui_->scroll(0,-preferences::scroll_speed());
00759 scrolling_ = true;
00760 }
00761
00762 if((key[SDLK_DOWN] && !menu_handler_.get_textbox().active()) || mousey > gui_->h()-scroll_threshold) {
00763 gui_->scroll(0,preferences::scroll_speed());
00764 scrolling_ = true;
00765 }
00766
00767 if((key[SDLK_LEFT] && !menu_handler_.get_textbox().active()) || mousex < scroll_threshold) {
00768 gui_->scroll(-preferences::scroll_speed(),0);
00769 scrolling_ = true;
00770 }
00771
00772 if((key[SDLK_RIGHT] && !menu_handler_.get_textbox().active()) || mousex > gui_->w()-scroll_threshold) {
00773 gui_->scroll(preferences::scroll_speed(),0);
00774 scrolling_ = true;
00775 }
00776
00777 if (middle_pressed) {
00778 const SDL_Rect& rect = gui_->map_outside_area();
00779 if (point_in_rect(mousex, mousey,rect)) {
00780
00781
00782
00783
00784 const double xdisp = ((1.0*mousex / rect.w) - 0.5);
00785 const double ydisp = ((1.0*mousey / rect.h) - 0.5);
00786
00787
00788 const double scroll_speed = 4.0 * preferences::scroll_speed();
00789
00790 const int xspeed = round_double(xdisp * scroll_speed);
00791 const int yspeed = round_double(ydisp * scroll_speed);
00792
00793 gui_->scroll(xspeed,yspeed);
00794 scrolling_ = true;
00795 }
00796 }
00797
00798 gui_->draw();
00799 if (!scrolling_) {
00800 if (was_scrolling) {
00801
00802 mouse_handler_.mouse_update(browse_);
00803 }
00804 gui_->delay(20);
00805 }
00806
00807 if(!browse_ && current_team().objectives_changed()) {
00808 dialogs::show_objectives(*gui_, level_, current_team().objectives());
00809 current_team().reset_objectives_changed();
00810 }
00811 }
00812
00813 static void trim_items(std::vector<std::string>& newitems) {
00814 if (newitems.size() > 5) {
00815 std::vector<std::string> subitems;
00816 subitems.push_back(newitems[0]);
00817 subitems.push_back(newitems[1]);
00818 subitems.push_back(newitems[newitems.size() / 3]);
00819 subitems.push_back(newitems[newitems.size() * 2 / 3]);
00820 subitems.push_back(newitems.back());
00821 newitems = subitems;
00822 }
00823 }
00824
00825 void play_controller::expand_autosaves(std::vector<std::string>& items)
00826 {
00827 savenames_.clear();
00828 for (unsigned int i = 0; i < items.size(); ++i) {
00829 if (items[i] == "AUTOSAVES") {
00830 items.erase(items.begin() + i);
00831 std::vector<std::string> newitems;
00832 std::vector<std::string> newsaves;
00833 for (unsigned int turn = status_.turn(); turn != 0; turn--) {
00834 std::string name = gamestate_.label + "-" + _("Auto-Save") + lexical_cast<std::string>(turn);
00835 if (save_game_exists(name)) {
00836 if(preferences::compress_saves()) {
00837 newsaves.push_back(name + ".gz");
00838 } else {
00839 newsaves.push_back(name);
00840 }
00841 if (turn == 1) {
00842 newitems.push_back(_("Back to start"));
00843 } else {
00844 newitems.push_back(_("Back to turn ") + lexical_cast<std::string>(turn));
00845 }
00846 }
00847 }
00848
00849
00850
00851 trim_items(newitems);
00852 trim_items(newsaves);
00853
00854 items.insert(items.begin()+i, newitems.begin(), newitems.end());
00855 savenames_.insert(savenames_.end(), newsaves.begin(), newsaves.end());
00856 break;
00857 }
00858 savenames_.push_back("");
00859 }
00860 }
00861
00862 void play_controller::expand_wml_commands(std::vector<std::string>& items)
00863 {
00864 wml_commands_.clear();
00865 for (unsigned int i = 0; i < items.size(); ++i) {
00866 if (items[i] == "wml") {
00867 items.erase(items.begin() + i);
00868 std::map<std::string, wml_menu_item*>& gs_wmi = gamestate_.wml_menu_items;
00869 if(gs_wmi.empty())
00870 break;
00871 std::vector<std::string> newitems;
00872
00873 char buf[50];
00874 const gamemap::location& hex = mouse_handler_.get_last_hex();
00875 snprintf(buf,sizeof(buf),"%d",hex.x+1);
00876 gamestate_.set_variable("x1", buf);
00877 snprintf(buf,sizeof(buf),"%d",hex.y+1);
00878 gamestate_.set_variable("y1", buf);
00879 scoped_xy_unit highlighted_unit("unit", hex.x, hex.y, units_);
00880
00881 std::map<std::string, wml_menu_item*>::iterator itor;
00882 for (itor = gs_wmi.begin(); itor != gs_wmi.end()
00883 && newitems.size() < MAX_WML_COMMANDS; ++itor) {
00884 config& show_if = itor->second->show_if;
00885 config filter_location = itor->second->filter_location;
00886 if ((show_if.empty()
00887 || game_events::conditional_passed(&units_, &show_if))
00888 && (filter_location.empty()
00889 || terrain_filter(&filter_location, map_, status_, units_)(hex))
00890 && (!itor->second->needs_select
00891 || gamestate_.last_selected.valid()))
00892 {
00893 wml_commands_.push_back(itor->second);
00894 std::string newitem = itor->second->description;
00895
00896
00897 push_back<std::string, char>(newitem, ' ');
00898 newitems.push_back(newitem);
00899 }
00900 }
00901 items.insert(items.begin()+i, newitems.begin(), newitems.end());
00902 break;
00903 }
00904 wml_commands_.push_back(NULL);
00905 }
00906 }
00907
00908 void play_controller::show_menu(const std::vector<std::string>& items_arg, int xloc, int yloc, bool context_menu)
00909 {
00910 std::vector<std::string> items = items_arg;
00911 hotkey::HOTKEY_COMMAND command;
00912 std::vector<std::string>::iterator i = items.begin();
00913 while(i != items.end()) {
00914 if (*i == "AUTOSAVES") {
00915
00916 command = hotkey::HOTKEY_LOAD_GAME;
00917 } else {
00918 command = hotkey::get_hotkey(*i).get_id();
00919 }
00920
00921 if(*i == "wml") {
00922 if(!context_menu || gui_->viewing_team() != gui_->playing_team()
00923 || events::commands_disabled || !teams_[gui_->viewing_team()].is_human()) {
00924 i = items.erase(i);
00925 continue;
00926 }
00927
00928 } else if(!can_execute_command(command)
00929 || (context_menu && !in_context_menu(command))) {
00930 i = items.erase(i);
00931 continue;
00932 }
00933 ++i;
00934 }
00935
00936
00937 expand_autosaves(items);
00938 expand_wml_commands(items);
00939
00940 if(items.empty())
00941 return;
00942
00943 command_executor::show_menu(items, xloc, yloc, context_menu, *gui_);
00944 }
00945
00946
00947
00948 bool play_controller::in_context_menu(hotkey::HOTKEY_COMMAND command) const
00949 {
00950 switch(command) {
00951
00952 case hotkey::HOTKEY_RECRUIT:
00953 case hotkey::HOTKEY_REPEAT_RECRUIT:
00954 case hotkey::HOTKEY_RECALL: {
00955
00956
00957 const unit_map::const_iterator leader = team_leader(player_number_,units_);
00958 if (leader != units_.end()) {
00959 return can_recruit_on(map_, leader->first, mouse_handler_.get_last_hex());
00960 } else {
00961 return false;
00962 }
00963 }
00964 default:
00965 return true;
00966 }
00967 }
00968
00969 std::string play_controller::get_action_image(hotkey::HOTKEY_COMMAND command, int index) const
00970 {
00971 if(index >= 0 && index < static_cast<int>(wml_commands_.size())) {
00972 wml_menu_item* const& wmi = wml_commands_[index];
00973 if(wmi != NULL) {
00974 return wmi->image.empty() ? game_config::wml_menu_image : wmi->image;
00975 }
00976 }
00977 return command_executor::get_action_image(command, index);
00978 }
00979
00980 hotkey::ACTION_STATE play_controller::get_action_state(hotkey::HOTKEY_COMMAND command) const
00981 {
00982 switch(command) {
00983 case hotkey::HOTKEY_DELAY_SHROUD:
00984 return current_team().auto_shroud_updates() ? hotkey::ACTION_OFF : hotkey::ACTION_ON;
00985 default:
00986 return hotkey::ACTION_STATELESS;
00987 }
00988 }
00989