bool playmp_controller::can_execute_command(hotkey::HOTKEY_COMMAND command, int index) const { bool res = true; switch (command){ case hotkey::HOTKEY_CLEAR_LABELS: res = !is_observer(); case hotkey::HOTKEY_SPEAK: case hotkey::HOTKEY_SPEAK_ALLY: case hotkey::HOTKEY_SPEAK_ALL: res = res && network::nconnections() > 0; break; case hotkey::HOTKEY_START_NETWORK: case hotkey::HOTKEY_STOP_NETWORK: res = is_observer(); break; case hotkey::HOTKEY_STOP_REPLAY: if (is_observer()){ network_processing_stopped_ = true; LOG_NG << "network processing stopped"; } break; default: return playsingle_controller::can_execute_command(command, index); } return res; }
void play_controller::init_side_begin() { mouse_handler_.set_side(current_side()); // If we are observers we move to watch next team if it is allowed if ((is_observer() && !current_team().get_disallow_observers()) || (current_team().is_local_human() && !this->is_replay())) { update_gui_to_player(current_side() - 1); } gui_->set_playing_team(size_t(current_side() - 1)); gamestate().gamedata_.last_selected = map_location::null_location(); }
bool playmp_controller::can_execute_command(const hotkey::hotkey_command& cmd, int index) const { hotkey::HOTKEY_COMMAND command = cmd.id; bool res = true; switch (command){ case hotkey::HOTKEY_ENDTURN: if (linger_) { bool has_next_scenario = !resources::gamedata->next_scenario().empty() && resources::gamedata->next_scenario() != "null"; return is_host() || !has_next_scenario; } else { return playsingle_controller::can_execute_command(cmd, index); } case hotkey::HOTKEY_SPEAK: case hotkey::HOTKEY_SPEAK_ALLY: case hotkey::HOTKEY_SPEAK_ALL: res = network::nconnections() > 0; break; case hotkey::HOTKEY_START_NETWORK: case hotkey::HOTKEY_STOP_NETWORK: res = is_observer(); break; case hotkey::HOTKEY_REPLAY_STOP: if (is_observer()){ network_processing_stopped_ = true; LOG_NG << "network processing stopped"; } break; default: return playsingle_controller::can_execute_command(cmd, index); } return res; }
bool playsingle_controller::hotkey_handler::can_execute_command(const hotkey::hotkey_command& cmd, int index) const { hotkey::HOTKEY_COMMAND command = cmd.id; bool res = true; switch (command){ case hotkey::HOTKEY_WML: { int prefixlen = wml_menu_hotkey_prefix.length(); if(cmd.command.compare(0, prefixlen, wml_menu_hotkey_prefix) != 0) { return false; } game_events::wmi_container::const_iterator it = gamestate().get_wml_menu_items().find(cmd.command.substr(prefixlen)); if(it == gamestate().get_wml_menu_items().end()) { return false; } return !(**it).is_synced() || play_controller_.can_use_synced_wml_menu(); } case hotkey::HOTKEY_UNIT_HOLD_POSITION: case hotkey::HOTKEY_END_UNIT_TURN: return !browse() && !linger() && !events::commands_disabled; case hotkey::HOTKEY_RECRUIT: case hotkey::HOTKEY_REPEAT_RECRUIT: case hotkey::HOTKEY_RECALL: return (!browse() || whiteboard_manager_->is_active()) && !linger() && !events::commands_disabled; case hotkey::HOTKEY_ENDTURN: return (!browse() || linger()) && !events::commands_disabled; case hotkey::HOTKEY_DELAY_SHROUD: return !linger() && (viewing_team().uses_fog() || viewing_team().uses_shroud()) && viewing_team_is_playing() && viewing_team().is_local_human() && !events::commands_disabled; case hotkey::HOTKEY_UPDATE_SHROUD: return !linger() && viewing_team_is_playing() && viewing_team().is_local_human() && !events::commands_disabled && viewing_team().auto_shroud_updates() == false; // Commands we can only do if in debug mode case hotkey::HOTKEY_CREATE_UNIT: case hotkey::HOTKEY_CHANGE_SIDE: case hotkey::HOTKEY_KILL_UNIT: return !events::commands_disabled && game_config::debug && play_controller_.get_map_const().on_board(mouse_handler_.get_last_hex()); case hotkey::HOTKEY_CLEAR_LABELS: res = !is_observer(); break; case hotkey::HOTKEY_LABEL_TEAM_TERRAIN: case hotkey::HOTKEY_LABEL_TERRAIN: { const terrain_label *label = gui()->labels().get_label(mouse_handler_.get_last_hex()); res = !events::commands_disabled && play_controller_.get_map_const().on_board(mouse_handler_.get_last_hex()) && !gui()->shrouded(mouse_handler_.get_last_hex()) && !is_observer() && (!label || !label->immutable()); break; } case hotkey::HOTKEY_CONTINUE_MOVE: { if(browse() || events::commands_disabled) return false; if( (menu_handler_.current_unit().valid()) && (menu_handler_.current_unit()->move_interrupted())) return true; const unit_map::const_iterator i = play_controller_.get_units_const().find(mouse_handler_.get_selected_hex()); if (!i.valid()) return false; return i->move_interrupted(); } case hotkey::HOTKEY_WB_TOGGLE: return !is_observer(); case hotkey::HOTKEY_WB_EXECUTE_ACTION: case hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS: return whiteboard_manager_->can_enable_execution_hotkeys(); case hotkey::HOTKEY_WB_DELETE_ACTION: return whiteboard_manager_->can_enable_modifier_hotkeys(); case hotkey::HOTKEY_WB_BUMP_UP_ACTION: case hotkey::HOTKEY_WB_BUMP_DOWN_ACTION: return whiteboard_manager_->can_enable_reorder_hotkeys(); case hotkey::HOTKEY_WB_SUPPOSE_DEAD: { //@todo re-enable this once we figure out a decent UI for suppose_dead return false; } default: return play_controller::hotkey_handler::can_execute_command(cmd, index); } return res; }
LEVEL_RESULT playsingle_controller::play_scenario( const config::const_child_itors &story, bool skip_replay) { uint32_t start = SDL_GetTicks(); // level_ // save game: [snapshort] in save file // new game: [scenario] in <scenarios>.cfg // Start music. BOOST_FOREACH (const config &m, level_.child_range("music")) { sound::play_music_config(m); } sound::commit_music_changes(); if(!skip_replay) { // show_story(*gui_, level_["name"], story); // gui2::show_story(*gui_, level_["name"], story); } gui_->labels().read(level_); // Read sound sources assert(soundsources_manager_ != NULL); BOOST_FOREACH (const config &s, level_.child_range("sound_source")) { soundsource::sourcespec spec(s); soundsources_manager_->add(spec); } uint32_t end_sound_sources = SDL_GetTicks(); posix_print("playsingle_controller::play_scenario, sound sources, used time: %u ms\n", end_sound_sources - start); set_victory_when_enemy_no_city(level_["victory_when_enemy_no_city"].to_bool(true)); end_level_data &end_level = get_end_level_data(); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carryover_add"].to_bool(); try { uint32_t end_entering_try = SDL_GetTicks(); posix_print("playsingle_controller::play_scenario, entering try, used time: %u ms\n", end_entering_try - end_sound_sources); fire_prestart(!loading_game_); uint32_t end_fire_prestart = SDL_GetTicks(); posix_print("playsingle_controller::play_scenario, fire_prestrt, used time: %u ms\n", end_fire_prestart - end_entering_try); init_gui(); fire_start(!loading_game_); gui_->recalculate_minimap(); // replaying_ = (recorder.at_end() == false); // Initialize countdown clock. std::vector<team>::iterator t; for(t = teams_.begin(); t != teams_.end(); ++t) { if (gamestate_.mp_settings().mp_countdown && !loading_game_ ){ t->set_countdown_time(1000 * gamestate_.mp_settings().mp_countdown_init_time); } } // if we loaded a save file in linger mode, skip to it. if (linger_) { //determine the bonus gold handling for this scenario const config end_cfg = level_.child_or_empty("endlevel"); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carr`yover_add"].to_bool(); end_level.gold_bonus = end_cfg["bonus"].to_bool(true); end_level.carryover_report = false; throw end_level_exception(SKIP_TO_LINGER); } // Avoid autosaving after loading, but still // allow the first turn to have an autosave. bool save = !loading_game_; for(; ; first_player_ = 1) { play_turn(save); save = true; } //end for loop } catch(game::load_game_exception& lge) { // Loading a new game is effectively a quit. // if (lge.game != "") { gamestate_ = game_state(); } throw lge; } catch (end_level_exception &end_level_exn) { LEVEL_RESULT end_level_result = end_level_exn.result; if (!end_level.custom_endlevel_music.empty()) { if (end_level_result == DEFEAT) { set_defeat_music_list(end_level.custom_endlevel_music); } else { set_victory_music_list(end_level.custom_endlevel_music); } } if (teams_.empty()) { //store persistent teams gamestate_.snapshot = config(); return VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event } const bool obs = is_observer(); if (end_level_result == DEFEAT || end_level_result == VICTORY) { gamestate_.classification().completion = (end_level_exn.result == VICTORY) ? "victory" : "defeat"; // If we're a player, and the result is victory/defeat, then send // a message to notify the server of the reason for the game ending. if (!obs) { config cfg; config& info = cfg.add_child("info"); info["type"] = "termination"; info["condition"] = "game over"; info["result"] = gamestate_.classification().completion; network::send_data(cfg, 0); } else { gui2::show_transient_message(gui_->video(),_("Game Over"), _("The game is over.")); return OBSERVER_END; } } if (end_level_result == QUIT) { return QUIT; } else if (end_level_result == DEFEAT) { gamestate_.classification().completion = "defeat"; game_events::fire("defeat"); if (!obs) { const std::string& defeat_music = select_defeat_music(); if(defeat_music.empty() != true) sound::play_music_once(defeat_music); return DEFEAT; } else { return QUIT; } } else if (end_level_result == VICTORY) { gamestate_.classification().completion = !end_level.linger_mode ? "running" : "victory"; game_events::fire("victory"); // // Play victory music once all victory events // are finished, if we aren't observers. // // Some scenario authors may use 'continue' // result for something that is not story-wise // a victory, so let them use [music] tags // instead should they want special music. // if (!obs && end_level.linger_mode) { const std::string& victory_music = select_victory_music(); if(victory_music.empty() != true) sound::play_music_once(victory_music); } // Add all the units that survived the scenario. LOG_NG << "Add units that survived the scenario to the recall list.\n"; //store all units that survived (recall list for the next scenario) in snapshot gamestate_.snapshot = config(); //store gold and report victory store_gold(obs); return VICTORY; } else if (end_level_result == SKIP_TO_LINGER) { LOG_NG << "resuming from loaded linger state...\n"; //as carryover information is stored in the snapshot, we have to re-store it after loading a linger state gamestate_.snapshot = config(); store_gold(); return VICTORY; } } // end catch catch(network::error& e) { bool disconnect = false; if(e.socket) { e.disconnect(); disconnect = true; } config snapshot; to_config(snapshot); savegame::game_savegame save(heros_, heros_start_, gamestate_, *gui_, snapshot); 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); if(disconnect) { throw network::error(); } else { return QUIT; } } return QUIT; }
LEVEL_RESULT playsingle_controller::play_scenario(const config& level) { LOG_NG << "in playsingle_controller::play_scenario()...\n"; // Start music. BOOST_FOREACH(const config &m, level.child_range("music")) { sound::play_music_config(m); } sound::commit_music_changes(); if(!this->is_skipping_replay()) { show_story(gui_->video(), get_scenario_name(), level.child_range("story")); } gui_->labels().read(level); // Read sound sources assert(soundsources_manager_ != NULL); BOOST_FOREACH(const config &s, level.child_range("sound_source")) { try { soundsource::sourcespec spec(s); soundsources_manager_->add(spec); } catch (bad_lexical_cast &) { ERR_NG << "Error when parsing sound_source config: bad lexical cast." << std::endl; ERR_NG << "sound_source config was: " << s.debug() << std::endl; ERR_NG << "Skipping this sound source..." << std::endl; } } LOG_NG << "entering try... " << (SDL_GetTicks() - ticks()) << "\n"; try { play_scenario_init(); // clears level config; this->saved_game_.remove_snapshot(); if (!is_regular_game_end() && !linger_) { play_scenario_main_loop(); } if (game_config::exit_at_end) { exit(0); } const bool is_victory = get_end_level_data_const().is_victory; if(gamestate().gamedata_.phase() <= game_data::PRESTART) { sdl::draw_solid_tinted_rectangle( 0, 0, gui_->video().getx(), gui_->video().gety(), 0, 0, 0, 1.0, gui_->video().getSurface() ); update_rect(0, 0, gui_->video().getx(), gui_->video().gety()); } ai_testing::log_game_end(); const end_level_data& end_level = get_end_level_data_const(); if (!end_level.transient.custom_endlevel_music.empty()) { if (!is_victory) { set_defeat_music_list(end_level.transient.custom_endlevel_music); } else { set_victory_music_list(end_level.transient.custom_endlevel_music); } } if (gamestate().board_.teams().empty()) { //store persistent teams saved_game_.set_snapshot(config()); return LEVEL_RESULT::VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event } if(linger_) { LOG_NG << "resuming from loaded linger state...\n"; //as carryover information is stored in the snapshot, we have to re-store it after loading a linger state saved_game_.set_snapshot(config()); if(!is_observer()) { persist_.end_transaction(); } return LEVEL_RESULT::VICTORY; } pump().fire(is_victory ? "victory" : "defeat"); { // Block for set_scontext_synced_base set_scontext_synced_base sync; pump().fire("scenario end"); } if(end_level.proceed_to_next_level) { gamestate().board_.heal_all_survivors(); } if(is_observer()) { gui2::show_transient_message(gui_->video(), _("Game Over"), _("The game is over.")); return LEVEL_RESULT::OBSERVER_END; } // If we're a player, and the result is victory/defeat, then send // a message to notify the server of the reason for the game ending. network::send_data(config_of ("info", config_of ("type", "termination") ("condition", "game over") ("result", is_victory ? "victory" : "defeat") )); // Play victory music once all victory events // are finished, if we aren't observers. // // Some scenario authors may use 'continue' // result for something that is not story-wise // a victory, so let them use [music] tags // instead should they want special music. const std::string& end_music = is_victory ? select_victory_music() : select_defeat_music(); if(end_music.empty() != true) { sound::play_music_once(end_music); } persist_.end_transaction(); return is_victory ? LEVEL_RESULT::VICTORY : LEVEL_RESULT::DEFEAT; } catch(const game::load_game_exception &) { // Loading a new game is effectively a quit. // if ( game::load_game_exception::game != "" ) { saved_game_ = saved_game(); } throw; } catch(network::error& e) { bool disconnect = false; if(e.socket) { e.disconnect(); disconnect = true; } scoped_savegame_snapshot snapshot(*this); savegame::ingame_savegame save(saved_game_, *gui_, preferences::save_compression_format()); 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); if(disconnect) { throw network::error(); } else { return LEVEL_RESULT::QUIT; } } return LEVEL_RESULT::QUIT; }
bool is_member(const network::connection player) const { return is_player(player) || is_observer(player); }
LEVEL_RESULT playsingle_controller::play_scenario( const config::const_child_itors &story, bool skip_replay) { LOG_NG << "in playsingle_controller::play_scenario()...\n"; // Start music. foreach (const config &m, level_.child_range("music")) { sound::play_music_config(m); } sound::commit_music_changes(); if(!skip_replay) { show_story(*gui_, level_["name"], story); } gui_->labels().read(level_); // Read sound sources assert(soundsources_manager_ != NULL); foreach (const config &s, level_.child_range("sound_source")) { soundsource::sourcespec spec(s); soundsources_manager_->add(spec); } set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true)); end_level_data &end_level = get_end_level_data(); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carryover_add"].to_bool(); bool past_prestart = false; LOG_NG << "entering try... " << (SDL_GetTicks() - ticks_) << "\n"; try { fire_prestart(!loading_game_); init_gui(); past_prestart = true; LOG_NG << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n"; events::raise_draw_event(); fire_start(!loading_game_); gui_->recalculate_minimap(); replaying_ = (recorder.at_end() == false); LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n"; // Initialize countdown clock. std::vector<team>::iterator t; for(t = teams_.begin(); t != teams_.end(); ++t) { if (gamestate_.mp_settings().mp_countdown && !loading_game_ ){ t->set_countdown_time(1000 * gamestate_.mp_settings().mp_countdown_init_time); } } // if we loaded a save file in linger mode, skip to it. if (linger_) { //determine the bonus gold handling for this scenario end_level.read(level_.child_or_empty("endlevel")); end_level.carryover_report = false; end_level.disabled = true; throw end_level_exception(SKIP_TO_LINGER); } // Avoid autosaving after loading, but still // allow the first turn to have an autosave. bool save = !loading_game_; ai_testing::log_game_start(); for(; ; first_player_ = 1) { play_turn(save); save = true; } //end for loop #ifdef _MSC_VER //MSVC claims that const game::load_game_exception& lge would be unreferenced... #pragma warning (push) #pragma warning (disable : 4101) #endif } catch(const game::load_game_exception& lge) { // Loading a new game is effectively a quit. // if (lge.game != "") { gamestate_ = game_state(); } throw; } catch (end_level_exception &end_level_exn) { if(!past_prestart) { draw_solid_tinted_rectangle( 0, 0, gui_->video().getx(), gui_->video().gety(), 0, 0, 0, 1.0, gui_->video().getSurface() ); update_rect(0, 0, gui_->video().getx(), gui_->video().gety()); } ai_testing::log_game_end(); LEVEL_RESULT end_level_result = end_level_exn.result; if (!end_level.custom_endlevel_music.empty()) { if (end_level_result == DEFEAT) { set_defeat_music_list(end_level.custom_endlevel_music); } else { set_victory_music_list(end_level.custom_endlevel_music); } } if (teams_.empty()) { //store persistent teams gamestate_.snapshot = config(); store_recalls(); return VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event } const bool obs = is_observer(); if (game_config::exit_at_end) { exit(0); } if (end_level_result == DEFEAT || end_level_result == VICTORY) { gamestate_.classification().completion = (end_level_exn.result == VICTORY) ? "victory" : "defeat"; // If we're a player, and the result is victory/defeat, then send // a message to notify the server of the reason for the game ending. if (!obs) { config cfg; config& info = cfg.add_child("info"); info["type"] = "termination"; info["condition"] = "game over"; info["result"] = gamestate_.classification().completion; network::send_data(cfg, 0); } else { gui2::show_transient_message(gui_->video(),_("Game Over"), _("The game is over.")); return OBSERVER_END; } } if (end_level_result == QUIT) { return QUIT; } else if (end_level_result == DEFEAT) { gamestate_.classification().completion = "defeat"; game_events::fire("defeat"); if (!obs) { const std::string& defeat_music = select_defeat_music(); if(defeat_music.empty() != true) sound::play_music_once(defeat_music); return DEFEAT; } else { return QUIT; } } else if (end_level_result == VICTORY) { gamestate_.classification().completion = !end_level.linger_mode ? "running" : "victory"; game_events::fire("victory"); // // Play victory music once all victory events // are finished, if we aren't observers. // // Some scenario authors may use 'continue' // result for something that is not story-wise // a victory, so let them use [music] tags // instead should they want special music. // if (!obs && end_level.linger_mode) { const std::string& victory_music = select_victory_music(); if(victory_music.empty() != true) sound::play_music_once(victory_music); } // Add all the units that survived the scenario. LOG_NG << "Add units that survived the scenario to the recall list.\n"; for(unit_map::iterator un = units_.begin(); un != units_.end(); ++un) { if (teams_[un->side() - 1].persistent()) { LOG_NG << "Added unit " << un->id() << ", " << un->name() << "\n"; un->new_turn(); un->new_scenario(); teams_[un->side() - 1].recall_list().push_back(*un); } } //store all units that survived (recall list for the next scenario) in snapshot gamestate_.snapshot = config(); store_recalls(); //store gold and report victory store_gold(obs); return VICTORY; } else if (end_level_result == SKIP_TO_LINGER) { LOG_NG << "resuming from loaded linger state...\n"; //as carryover information is stored in the snapshot, we have to re-store it after loading a linger state gamestate_.snapshot = config(); store_recalls(); store_gold(); return VICTORY; } } // end catch catch(network::error& e) { bool disconnect = false; if(e.socket) { e.disconnect(); disconnect = true; } savegame::game_savegame save(gamestate_, *gui_, to_config(), preferences::compress_saves()); 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); if(disconnect) { throw network::error(); } else { return QUIT; } } return QUIT; }
LEVEL_RESULT playsingle_controller::play_scenario( const config::const_child_itors &story, bool skip_replay) { LOG_NG << "in playsingle_controller::play_scenario()...\n"; // Start music. BOOST_FOREACH(const config &m, level_.child_range("music")) { sound::play_music_config(m); } sound::commit_music_changes(); if(!skip_replay) { show_story(*gui_, level_["name"], story); } gui_->labels().read(level_); // Read sound sources assert(soundsources_manager_ != NULL); BOOST_FOREACH(const config &s, level_.child_range("sound_source")) { try { soundsource::sourcespec spec(s); soundsources_manager_->add(spec); } catch (bad_lexical_cast &) { ERR_NG << "Error when parsing sound_source config: bad lexical cast." << std::endl; ERR_NG << "sound_source config was: " << s.debug() << std::endl; ERR_NG << "Skipping this sound source..." << std::endl; } } set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true)); set_remove_from_carryover_on_defeat(level_["remove_from_carryover_on_defeat"].to_bool(true)); end_level_data &end_level = get_end_level_data(); end_level.carryover_percentage = level_["carryover_percentage"].to_int(game_config::gold_carryover_percentage); end_level.carryover_add = level_["carryover_add"].to_bool(); bool past_prestart = false; LOG_NG << "entering try... " << (SDL_GetTicks() - ticks_) << "\n"; try { possible_end_play_signal signal = play_scenario_init(end_level, past_prestart); if (!signal) { signal = play_scenario_main_loop(end_level, past_prestart); } if (signal) { switch (boost::apply_visitor( get_signal_type(), *signal )) { //BEGIN CASES case END_TURN: assert(false && "end turn signal propogated to playsingle_controller::play_scenario. This results in terminate!"); throw 42; case END_LEVEL: if(!past_prestart) { sdl::draw_solid_tinted_rectangle( 0, 0, gui_->video().getx(), gui_->video().gety(), 0, 0, 0, 1.0, gui_->video().getSurface() ); update_rect(0, 0, gui_->video().getx(), gui_->video().gety()); } ai_testing::log_game_end(); LEVEL_RESULT end_level_result = boost::apply_visitor( get_result(), *signal ); if (!end_level.transient.custom_endlevel_music.empty()) { if (end_level_result == DEFEAT) { set_defeat_music_list(end_level.transient.custom_endlevel_music); } else { set_victory_music_list(end_level.transient.custom_endlevel_music); } } if (gamestate_.board_.teams().empty()) { //store persistent teams saved_game_.set_snapshot(config()); return VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event } const bool obs = is_observer(); if (game_config::exit_at_end) { exit(0); } if (end_level_result == DEFEAT || end_level_result == VICTORY) { saved_game_.classification().completion = (end_level_result == VICTORY) ? "victory" : "defeat"; // If we're a player, and the result is victory/defeat, then send // a message to notify the server of the reason for the game ending. if (!obs) { config cfg; config& info = cfg.add_child("info"); info["type"] = "termination"; info["condition"] = "game over"; info["result"] = saved_game_.classification().completion; network::send_data(cfg, 0); } else { gui2::show_transient_message(gui_->video(),_("Game Over"), _("The game is over.")); return OBSERVER_END; } } if (end_level_result == QUIT) { return QUIT; } else if (end_level_result == DEFEAT) { saved_game_.classification().completion = "defeat"; game_events::fire("defeat"); if (!obs) { const std::string& defeat_music = select_defeat_music(); if(defeat_music.empty() != true) sound::play_music_once(defeat_music); persist_.end_transaction(); return DEFEAT; } else { return QUIT; } } else if (end_level_result == VICTORY) { saved_game_.classification().completion = !end_level.transient.linger_mode ? "running" : "victory"; game_events::fire("victory"); // // Play victory music once all victory events // are finished, if we aren't observers. // // Some scenario authors may use 'continue' // result for something that is not story-wise // a victory, so let them use [music] tags // instead should they want special music. // if (!obs && end_level.transient.linger_mode) { const std::string& victory_music = select_victory_music(); if(victory_music.empty() != true) sound::play_music_once(victory_music); } // Add all the units that survived the scenario. // this function doesn't move unit to the recalllist anymore i just keep this name to prevent merging conflicts. LOG_NG << "Add units that survived the scenario to the recall list.\n"; gamestate_.board_.all_survivors_to_recall(); saved_game_.remove_snapshot(); if(!is_observer()) { persist_.end_transaction(); } return VICTORY; } else if (end_level_result == SKIP_TO_LINGER) { LOG_NG << "resuming from loaded linger state...\n"; //as carryover information is stored in the snapshot, we have to re-store it after loading a linger state saved_game_.set_snapshot(config()); if(!is_observer()) { persist_.end_transaction(); } return VICTORY; } break; //END CASES } // END SWITCH } //end if } catch(const game::load_game_exception &) { // Loading a new game is effectively a quit. // if ( game::load_game_exception::game != "" ) { saved_game_ = saved_game(); } throw; } catch(network::error& e) { bool disconnect = false; if(e.socket) { e.disconnect(); disconnect = true; } savegame::ingame_savegame save(saved_game_, *gui_, to_config(), preferences::save_compression_format()); 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); if(disconnect) { throw network::error(); } else { return QUIT; } } return QUIT; }
bool playsingle_controller::can_execute_command(const hotkey::hotkey_command& cmd, int index) const { hotkey::HOTKEY_COMMAND command = cmd.id; bool res = true; switch (command) { case hotkey::HOTKEY_WML: //code mixed from play_controller::show_menu and code here return (gui_->viewing_team() == gui_->playing_team()) && !events::commands_disabled && gamestate_.board_.teams()[gui_->viewing_team()].is_human() && !linger_ && !browse_; case hotkey::HOTKEY_UNIT_HOLD_POSITION: case hotkey::HOTKEY_END_UNIT_TURN: return !browse_ && !linger_ && !events::commands_disabled; case hotkey::HOTKEY_RECRUIT: case hotkey::HOTKEY_REPEAT_RECRUIT: case hotkey::HOTKEY_RECALL: return (!browse_ || whiteboard_manager_->is_active()) && !linger_ && !events::commands_disabled; case hotkey::HOTKEY_ENDTURN: return (!browse_ || linger_) && !events::commands_disabled; case hotkey::HOTKEY_DELAY_SHROUD: return !linger_ && (gamestate_.board_.teams()[gui_->viewing_team()].uses_fog() || gamestate_.board_.teams()[gui_->viewing_team()].uses_shroud()) && !events::commands_disabled; case hotkey::HOTKEY_UPDATE_SHROUD: return !linger_ && player_number_ == gui_->viewing_side() && !events::commands_disabled && gamestate_.board_.teams()[gui_->viewing_team()].auto_shroud_updates() == false; // Commands we can only do if in debug mode case hotkey::HOTKEY_CREATE_UNIT: case hotkey::HOTKEY_CHANGE_SIDE: case hotkey::HOTKEY_KILL_UNIT: return !events::commands_disabled && game_config::debug && gamestate_.board_.map().on_board(mouse_handler_.get_last_hex()); case hotkey::HOTKEY_CLEAR_LABELS: res = !is_observer(); break; case hotkey::HOTKEY_LABEL_TEAM_TERRAIN: case hotkey::HOTKEY_LABEL_TERRAIN: { const terrain_label *label = resources::screen->labels().get_label(mouse_handler_.get_last_hex()); res = !events::commands_disabled && gamestate_.board_.map().on_board(mouse_handler_.get_last_hex()) && !gui_->shrouded(mouse_handler_.get_last_hex()) && !is_observer() && (!label || !label->immutable()); break; } case hotkey::HOTKEY_CONTINUE_MOVE: { if(browse_ || events::commands_disabled) return false; if( (menu_handler_.current_unit().valid()) && (menu_handler_.current_unit()->move_interrupted())) return true; const unit_map::const_iterator i = gamestate_.board_.units().find(mouse_handler_.get_selected_hex()); if (!i.valid()) return false; return i->move_interrupted(); } case hotkey::HOTKEY_WB_TOGGLE: return !is_observer(); case hotkey::HOTKEY_WB_EXECUTE_ACTION: case hotkey::HOTKEY_WB_EXECUTE_ALL_ACTIONS: return whiteboard_manager_->can_enable_execution_hotkeys(); case hotkey::HOTKEY_WB_DELETE_ACTION: return whiteboard_manager_->can_enable_modifier_hotkeys(); case hotkey::HOTKEY_WB_BUMP_UP_ACTION: case hotkey::HOTKEY_WB_BUMP_DOWN_ACTION: return whiteboard_manager_->can_enable_reorder_hotkeys(); case hotkey::HOTKEY_WB_SUPPOSE_DEAD: { //@todo re-enable this once we figure out a decent UI for suppose_dead return false; } default: return play_controller::can_execute_command(cmd, index); } return res; }
void play_controller::init(CVideo& video, const config& level) { gui2::dialogs::loading_screen::display(video, [this, &video, &level]() { gui2::dialogs::loading_screen::progress("load level"); LOG_NG << "initializing game_state..." << (SDL_GetTicks() - ticks()) << std::endl; gamestate_.reset(new game_state(level, *this, tdata_)); resources::gameboard = &gamestate().board_; resources::gamedata = &gamestate().gamedata_; resources::tod_manager = &gamestate().tod_manager_; resources::units = &gamestate().board_.units_; resources::filter_con = &gamestate(); resources::undo_stack = &undo_stack(); resources::game_events = gamestate().events_manager_.get(); resources::lua_kernel = gamestate().lua_kernel_.get(); gamestate_->init(level, *this); resources::tunnels = gamestate().pathfind_manager_.get(); LOG_NG << "initializing whiteboard..." << (SDL_GetTicks() - ticks()) << std::endl; gui2::dialogs::loading_screen::progress("init whiteboard"); whiteboard_manager_.reset(new wb::manager()); resources::whiteboard = whiteboard_manager_; LOG_NG << "loading units..." << (SDL_GetTicks() - ticks()) << std::endl; gui2::dialogs::loading_screen::progress("load units"); preferences::encounter_all_content(gamestate().board_); LOG_NG << "initializing theme... " << (SDL_GetTicks() - ticks()) << std::endl; gui2::dialogs::loading_screen::progress("init theme"); const config& theme_cfg = controller_base::get_theme(game_config_, level["theme"]); LOG_NG << "building terrain rules... " << (SDL_GetTicks() - ticks()) << std::endl; gui2::dialogs::loading_screen::progress("build terrain"); gui_.reset(new game_display(gamestate().board_, video, whiteboard_manager_, *gamestate().reports_, gamestate().tod_manager_, theme_cfg, level)); if (!gui_->video().faked()) { if (saved_game_.mp_settings().mp_countdown) gui_->get_theme().modify_label("time-icon", _ ("time left for current turn")); else gui_->get_theme().modify_label("time-icon", _ ("current local time")); } gui2::dialogs::loading_screen::progress("init display"); mouse_handler_.set_gui(gui_.get()); menu_handler_.set_gui(gui_.get()); resources::screen = gui_.get(); LOG_NG << "done initializing display... " << (SDL_GetTicks() - ticks()) << std::endl; LOG_NG << "building gamestate to gui and whiteboard... " << (SDL_GetTicks() - ticks()) << std::endl; // This *needs* to be created before the show_intro and show_map_scene // as that functions use the manager state_of_game // Has to be done before registering any events! gamestate().set_game_display(gui_.get()); gui2::dialogs::loading_screen::progress("init lua"); if(gamestate().first_human_team_ != -1) { gui_->set_team(gamestate().first_human_team_); } else if(is_observer()) { // Find first team that is allowed to be observed. // If not set here observer would be without fog until // the first turn of observable side size_t i; for (i=0; i < gamestate().board_.teams().size(); ++i) { if (!gamestate().board_.teams()[i].get_disallow_observers()) { gui_->set_team(i); } } } init_managers(); gui2::dialogs::loading_screen::progress("start game"); //loadscreen_manager->reset(); gamestate().gamedata_.set_phase(game_data::PRELOAD); gamestate().lua_kernel_->load_game(level); plugins_context_.reset(new plugins_context("Game")); plugins_context_->set_callback("save_game", [this](const config& cfg) { save_game_auto(cfg["filename"]); }, true); plugins_context_->set_callback("save_replay", [this](const config& cfg) { save_replay_auto(cfg["filename"]); }, true); plugins_context_->set_callback("quit", throw_end_level(), false); plugins_context_->set_accessor_string("scenario_name", [this](config) { return get_scenario_name(); }); }); //Do this after the loadingscreen, so that ita happens in the main thread. gui_->join(); }