Пример #1
0
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;
}
Пример #2
0
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();
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #6
0
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;
}
Пример #7
0
	bool is_member(const network::connection player) const
	{ return is_player(player) || is_observer(player); }
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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();
}