possible_end_play_signal playsingle_controller::play_scenario_init(end_level_data & /*eld*/, bool & past_prestart) {
    // At the beginning of the scenario, save a snapshot as replay_start
    if(saved_game_.replay_start().empty()) {
        saved_game_.replay_start() = to_config();
    }
    HANDLE_END_PLAY_SIGNAL( fire_preload() );

    replaying_ = (recorder.at_end() == false);

    if(!loading_game_ )
    {
        if(replaying_)
        {
            //can this codepath be reached ?
            //note this when we are entering an mp game and see the 'replay' of the game
            //this path is not reached because we receive the replay later
            config* pstart = recorder.get_next_action();
            assert(pstart->has_child("start"));
        }
        else
        {
            assert(recorder.empty());
            recorder.add_start();
            recorder.get_next_action();
        }
        //we can only use a set_scontext_synced with a non empty recorder.
        set_scontext_synced sync;

        HANDLE_END_PLAY_SIGNAL( fire_prestart() );
        init_gui();
        past_prestart = true;
        LOG_NG << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n";

        events::raise_draw_event();
        HANDLE_END_PLAY_SIGNAL( fire_start(true) );
        gui_->recalculate_minimap();
    }
    else
    {
        init_gui();
        past_prestart = true;
        events::raise_draw_event();
        HANDLE_END_PLAY_SIGNAL( fire_start(false) );
        gui_->recalculate_minimap();
    }
    return boost::none;
}
Beispiel #2
0
void replay_controller::reset_replay()
{
	DBG_REPLAY << "replay_controller::reset_replay\n";

	gui_->clear_chat_messages();
	is_playing_ = false;
	player_number_ = 1;
	current_turn_ = 1;
	it_is_a_new_turn_ = true;
	skip_replay_ = false;
	tod_manager_= tod_manager_start_;
	recorder.start_replay();
	recorder.set_skip(false);
	units_ = units_start_;
	gamestate_ = gamestate_start_;
	teams_ = teams_start_;
	if (events_manager_ ){
		// NOTE: this double reset is required so that the new
		// instance of game_events::manager isn't created before the
		// old manager is actually destroyed (triggering an assertion
		// failure)
		events_manager_.reset();
		events_manager_.reset(new game_events::manager(level_));
	}

	gui_->labels().read(level_);

	resources::gamedata->rng().seed_random(level_["random_seed"], level_["random_calls"]);
	statistics::fresh_stats();
	set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true));

	// Add era events for MP game.
	if (const config &era_cfg = level_.child("era")) {
		game_events::add_events(era_cfg.child_range("event"), "era_events");
	}

	// Scenario initialization. (c.f. playsingle_controller::play_scenario())
	fire_preload();
	if(true){ //block for set_scontext_synced
		config* pstart = recorder.get_next_action();
		assert(pstart->has_child("start"));
		/*
			use this after recorder.add_synced_command
			because set_scontext_synced sets the checkup to the last added command
		*/
		set_scontext_synced sync;
		
		fire_prestart(true);
		init_gui();
		fire_start(true);
	}
	// Since we did not fire the start event, it_is_a_new_turn_ has the wrong value.
	it_is_a_new_turn_ = true;
	update_gui();

	reset_replay_ui();
}
Beispiel #3
0
void play_controller::start_game()
{
    fire_preload();

    if(!gamestate().start_event_fired_)
    {
        gamestate().start_event_fired_ = true;
        resources::recorder->add_start_if_not_there_yet();
        resources::recorder->get_next_action();

        set_scontext_synced sync;

        fire_prestart();
        if (is_regular_game_end()) {
            return;
        }

        for ( int side = gamestate().board_.teams().size(); side != 0; --side )
            actions::clear_shroud(side, false, false);

        init_gui();
        LOG_NG << "first_time..." << (is_skipping_replay() ? "skipping" : "no skip") << "\n";

        events::raise_draw_event();
        fire_start();
        if (is_regular_game_end()) {
            return;
        }
        sync.do_final_checkup();
        gui_->recalculate_minimap();
        // Initialize countdown clock.
        for (const team& t : gamestate().board_.teams())
        {
            if (saved_game_.mp_settings().mp_countdown) {
                t.set_countdown_time(1000 * saved_game_.mp_settings().mp_countdown_init_time);
            }
        }
    }
    else
    {
        init_gui();
        events::raise_draw_event();
        gamestate().gamedata_.set_phase(game_data::PLAY);
        gui_->recalculate_minimap();
    }
}
void replay_controller::init(){
	DBG_REPLAY << "in replay_controller::init()...\n";

	//guarantee the cursor goes back to 'normal' at the end of the level
	const cursor::setter cursor_setter(cursor::NORMAL);
	init_replay_display();

	fire_prestart(true);
	init_gui();
	statistics::fresh_stats();
	set_victory_when_enemies_defeated(
		utils::string_bool(level_["victory_when_enemies_defeated"], true));

	DBG_REPLAY << "first_time..." << (recorder.is_skipping() ? "skipping" : "no skip") << "\n";

	fire_start(!loading_game_);
	update_gui();

	units_start_ = units_;
	teams_start_ = teams_;
}
void replay_controller::reset_replay(){
	gui_->clear_chat_messages();
	is_playing_ = false;
	player_number_ = 1;
	current_turn_ = 1;
	skip_replay_ = false;
	tod_manager_= tod_manager_start_;
	recorder.start_replay();
	recorder.set_skip(false);
	units_ = units_start_;
	gamestate_ = gamestate_start_;
	teams_ = teams_start_;
	statistics::fresh_stats();
	if (events_manager_ ){
		// NOTE: this double reset is required so that the new
		// instance of game_events::manager isn't created before the
		// old manager is actually destroyed (triggering an assertion
		// failure)
		events_manager_.reset();
		events_manager_.reset(new game_events::manager(level_));
	}

	gui_->new_turn();
	gui_->invalidate_game_status();
	events::raise_draw_event();
	(*gui_).invalidate_all();
	(*gui_).draw();

	fire_prestart(true);
	fire_start(!loading_game_);
	gui_->new_turn();
	gui_->invalidate_game_status();
	events::raise_draw_event();
	(*gui_).invalidate_all();
	(*gui_).draw();
	gui_->set_team(player_number_-1, show_everything_);
	//gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false);

	buttons_.reset_buttons();
}
void replay_controller::reset_replay(){
	gui::button* b = gui_->find_button("button-playreplay");
	if (b != NULL) { b->release(); }
	b = gui_->find_button("button-stopreplay");
	if (b != NULL) { b->release(); }
	gui_->clear_chat_messages();
	is_playing_ = false;
	player_number_ = 1;
	current_turn_ = 1;
	tod_manager_= tod_manager_start_;
	recorder.start_replay();
	units_ = units_start_;
	gamestate_ = gamestate_start_;
	teams_ = teams_start_;
	statistics::fresh_stats();
	if (events_manager_ ){
		// NOTE: this double reset is required so that the new
		// instance of game_events::manager isn't created before the
		// old manager is actually destroyed (triggering an assertion
		// failure)
		events_manager_.reset();
		events_manager_.reset(new game_events::manager(level_));
	}

	gui_->new_turn();
	gui_->invalidate_game_status();
	events::raise_draw_event();
	(*gui_).invalidate_all();
	(*gui_).draw();

	fire_prestart(true);
	fire_start(!loading_game_);
	gui_->new_turn();
	gui_->invalidate_game_status();
	events::raise_draw_event();
	(*gui_).invalidate_all();
	(*gui_).draw();
	b = gui_->find_button("button-resetreplay");
	if (b != NULL) { b->release(); }
}
void replay_controller::reset_replay(){

	gui_->clear_chat_messages();
	is_playing_ = false;
	player_number_ = 1;
	current_turn_ = 1;
	it_is_a_new_turn_ = true;
	skip_replay_ = false;
	tod_manager_= tod_manager_start_;
	recorder.start_replay();
	recorder.set_skip(false);
	units_ = units_start_;
	gamestate_ = gamestate_start_;
	teams_ = teams_start_;
	if (events_manager_ ){
		// NOTE: this double reset is required so that the new
		// instance of game_events::manager isn't created before the
		// old manager is actually destroyed (triggering an assertion
		// failure)
		events_manager_.reset();
		events_manager_.reset(new game_events::manager(level_));
	}

	gui_->labels().read(level_);

	statistics::fresh_stats();
	set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true));

	// Add era events for MP game.
	if (const config &era_cfg = level_.child("era")) {
		game_events::add_events(era_cfg.child_range("event"), "era_events");
	}

	fire_prestart(true);
	init_gui();
	fire_start(true);
	update_gui();

	reset_replay_ui();
}
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::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;
}
void replay_controller::reset_replay()
{
	DBG_REPLAY << "replay_controller::reset_replay\n";

	gui_->get_chat_manager().clear_chat_messages();
	is_playing_ = false;
	player_number_ = 1;
	current_turn_ = 1;
	it_is_a_new_turn_ = true;
	skip_replay_ = false;
	gamestate_.tod_manager_= tod_manager_start_;
	recorder.start_replay();
	recorder.set_skip(false);
	saved_game_ = saved_game_start_;
	gamestate_.board_ = gameboard_start_;
	gui_->change_display_context(&gamestate_.board_); //this doesn't change the pointer value, but it triggers the gui to update the internal terrain builder object,
						   //idk what the consequences of not doing that are, but its probably a good idea to do it, esp. if layout
						   //of game_board changes in the future
	if (events_manager_ ){
		// NOTE: this double reset is required so that the new
		// instance of game_events::manager isn't created before the
		// old manager is actually destroyed (triggering an assertion
		// failure)
		events_manager_.reset();
		events_manager_.reset(new game_events::manager(level_));
	}

	gui_->labels().read(level_);

	resources::gamedata->rng().seed_random(level_["random_seed"], level_["random_calls"]);
	statistics::fresh_stats();
	set_victory_when_enemies_defeated(level_["victory_when_enemies_defeated"].to_bool(true));

	resources::screen->recalculate_minimap();
	resources::screen->invalidate_all();
	resources::screen->rebuild_all();

	// Add era events for MP game.
	if (const config &era_cfg = level_.child("era")) {
		game_events::add_events(era_cfg.child_range("event"), "era_events");
	}

	// Scenario initialization. (c.f. playsingle_controller::play_scenario())
	fire_preload();
	if(true){ //block for set_scontext_synced
		if(recorder.add_start_if_not_there_yet())
		{
			ERR_REPLAY << "inserted missing [start]" << std::endl;
		}
		config* pstart = recorder.get_next_action();
		assert(pstart->has_child("start"));
		/*
			use this after recorder.add_synced_command
			because set_scontext_synced sets the checkup to the last added command
		*/
		set_scontext_synced sync;

		fire_prestart();
		init_gui();
		fire_start(true);
	}
	// Since we did not fire the start event, it_is_a_new_turn_ has the wrong value.
	it_is_a_new_turn_ = true;
	update_gui();

	reset_replay_ui();
}