Пример #1
0
int make_move(const void* pstate, ChoiceIndex hold)
{
  const GameState* state = pstate;
  int player = ai_current_player();

  switch (hold)
  {
    // hold and pass
    case 0:  
      DEBUG("P%d: Hold %+d points\n", player, state->turn_total[player]);
      ai_add_player_score(player, state->turn_total[player]);
      SET(state->turn_total[player], 0);
      if (ai_next_player())
      {
        play_turn(state);
      }
      return 1;

    // roll again      
    case 1:
      play_turn(state);
      return 1;
      
    default:
      assert(0);
      return 0;
  }
}
Пример #2
0
int die_rolled(const void* pstate, ChoiceIndex die)
{
  const GameState* state = pstate;
  int player = ai_current_player();
  DEBUG("P%d: Roll %d\n", player, die);
  
  switch (die)
  {
    case 0:
      // forfeit turn
      SET(state->turn_total[player], 0);
      if (ai_next_player())
      {
        play_turn(state);
      }
      return 1;
    
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
      // add die roll to turn total
      SET(state->turn_total[player], state->turn_total[player] + die + 1);
      DEBUG("P%d: Added %+d points -> %d\n", player, die+1, state->turn_total[player]);
      // roll or hold?
      ai_choice(state, 0, make_move, 0, 0x3);
      return 1;
      
    default:
      assert(0);
      return 0;
  }
}
void replay_controller::play_replay(){

	if (recorder.at_end()){
		return;
	}

	try{
		is_playing_ = true;
		buttons_.playback_should_start();

		DBG_REPLAY << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";
		for(; !recorder.at_end() && is_playing_; first_player_ = 1) {
			play_turn();
		} //end for loop
		
		if (!is_playing_) {
			gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false);
		}
	}
	catch(end_level_exception& e){
		if (e.result == QUIT) { throw e; }
	}
	
	buttons_.playback_should_stop(is_playing_);
}
Пример #4
0
possible_end_play_signal playsingle_controller::play_scenario_main_loop(end_level_data & end_level, bool & /*past_prestart*/) {
    LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";

    // Initialize countdown clock.
    std::vector<team>::const_iterator t;
    for(t = gamestate_.board_.teams().begin(); t != gamestate_.board_.teams().end(); ++t) {
        if (saved_game_.mp_settings().mp_countdown && !loading_game_ ) {
            t->set_countdown_time(1000 * saved_game_.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("end_level_data"));
        end_level.transient.carryover_report = false;
        end_level.transient.disabled = true;
        end_level_struct els = { SKIP_TO_LINGER };
        return possible_end_play_signal ( els );
        //throw end_level_exception(SKIP_TO_LINGER);
    }

    // Avoid autosaving after loading, but still
    // allow the first turn to have an autosave.
    do_autosaves_ = !loading_game_;
    ai_testing::log_game_start();
    for(; ; first_player_ = 1) {
        PROPOGATE_END_PLAY_SIGNAL( play_turn() );
        do_autosaves_ = true;
    } //end for loop
    return boost::none;
}
possible_end_play_signal replay_controller::play_replay_main_loop() {
	DBG_REPLAY << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";
	for(; !recorder.at_end() && is_playing_; first_player_ = 1) {
		PROPOGATE_END_PLAY_SIGNAL ( play_turn() );
	}
	return boost::none;
}
Пример #6
0
void playsingle_controller::play_scenario_main_loop()
{
	LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks()) << "\n";


	// Avoid autosaving after loading, but still
	// allow the first turn to have an autosave.
	ai_testing::log_game_start();
	if(gamestate().board_.teams().empty())
	{
		ERR_NG << "Playing game with 0 teams." << std::endl;
	}
	while(true) {
		try {
			play_turn();
			if (is_regular_game_end()) {
				turn_data_.send_data();
				return;
			}
			gamestate_->player_number_ = 1;
		}
		catch(const reset_gamestate_exception& ex) {
			//
			// TODO:
			//
			// The MP replay feature still doesn't work properly (causes OOS)
			// because:
			//
			// 1) The undo stack is not reset along with the gamestate (fixed).
			// 2) The server_request_number_ is not reset along with the
			//    gamestate (fixed).
			// 3) chat and other unsynced actions are inserted in the middle of
			//    the replay bringing the replay_pos in unorder (fixed).
			// 4) untracked changes in side controllers are lost when resetting
			//    gamestate (fixed).
			// 5) The game should have a stricter check for whether the loaded
			//    game is actually a parent of this game.
			// 6) If an action was undone after a game was saved it can cause
			//    OOS if the undone action is in the snapshot of the saved
			//    game (luckily this is never the case for autosaves).
			//
			boost::dynamic_bitset<> local_players;
			local_players.resize(gamestate().board_.teams().size(), true);
			//Preserve side controllers, becasue we won't get the side controoller updates again when replaying.
			for(size_t i = 0; i < local_players.size(); ++i) {
				local_players[i] = gamestate().board_.teams()[i].is_local();
			}
			reset_gamestate(*ex.level, (*ex.level)["replay_pos"]);
			for(size_t i = 0; i < local_players.size(); ++i) {
				resources::gameboard->teams()[i].set_local(local_players[i]);
			}
			play_scenario_init();
			replay_.reset(new replay_controller(*this, false, ex.level));
			if(ex.start_replay) {
				replay_->play_replay();
			}
		}
	} //end for loop
}
Пример #7
0
void play_game(const GameState* state)
{
  while (!is_game_over(state))
  {
    print_board(state);
    play_turn(state);
  }
}
Пример #8
0
int			main(int argc, char **argv)
{
    if (main_init(argc, argv) == -1)
        sig_handler(-1);
    while (42)
    {
        play_turn();
    }
    exit_shmem();
    return (EXIT_SUCCESS);
}
void replay_controller::replay_next_turn(){
	is_playing_ = true;
	play_turn();

 	if (!skip_replay_){
		gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false);
	}
	is_playing_ = false;
	gui::button* b = gui_->find_button("button-nextturn");
	if (b != NULL) { b->release(); }
}
void replay_controller::replay_next_turn(){
	is_playing_ = true;
	buttons_.playback_should_start();
	
	play_turn();

 	if (!skip_replay_ || !is_playing_){
		gui_->scroll_to_leader(units_, player_number_,game_display::ONSCREEN,false);
	}

	buttons_.playback_should_stop(is_playing_);
}
possible_end_play_signal replay_controller::replay_next_turn(){
	is_playing_ = true;
	replay_ui_playback_should_start();

	PROPOGATE_END_PLAY_SIGNAL( play_turn() );

 	if (!skip_replay_ || !is_playing_){
		gui_->scroll_to_leader(player_number_,game_display::ONSCREEN,false);
	}

	replay_ui_playback_should_stop();
	return boost::none;
}
Пример #12
0
int make_move_0(const GameState* state)
{
  int d1 = state->d1;
  int d2 = state->d2;
  int player = ai_current_player();
  DEBUG("P%d dice %d %d\n", player, d1, d2);
  ChoiceMask mask = 0;
  // entering from bar has priority
  if (state->bar[player])
  {
    if (reenter_from_bar(state, player, d1))
    {
      SET(state->d1, 0);
      d1 = 0;
    }
    if (reenter_from_bar(state, player, d2))
    {
      SET(state->d2, 0);
      d2 = 0;
    }
  }
  // player can move any of 24 points
  // TODO: bearing off rules
  for (int i=0; i<24; i++)
  {
    // does this point have a valid move?
    if (state->points[PT(player,i)].occupied == player+1 &&
        (is_valid_move(state,player,i,d1) || is_valid_move(state,player,i,d2) || is_valid_move(state,player,i,d1+d2)))
    {
      mask |= (1<<i);
    }
  }
  if (mask != 0)
  {
    // try each of our pieces
    if (ai_choice(state, 0, make_move_1, 0, mask) == 0)
      mask = 0;
  }
  // none are valid, so player passes
  if (mask == 0)
  {
    DEBUG("P%d no moves\n", player);
    if (ai_next_player())
      play_turn(state); // if in search mode
  }
  return 1;
}
Пример #13
0
int make_move_2(const void* pstate, ChoiceIndex index)
{
  const GameState* state = pstate;
  int d1 = state->d1;
  int d2 = state->d2;
  if (index == 3)
    SWAP(d1,d2);
  // make moves, either one at a time or together
  int pt = state->point_to_move;
  //print_board(state); printf("0 %d %d %d\n", ai_current_player(), index, pt);
  if (index != 1)
  {
    int m1 = make_move(state, pt, d1);
    // return failure if move is invalid
    // or if we bearoff but have a move remaining (TODO: prune earlier)
    if (m1 == MOVE_INVALID)
      return 0;
    if (m1 == MOVE_BEAROFF && index != 0)
      return 0;
    pt -= d1;
  }
  //print_board(state); printf("1 %d %d %d\n", ai_current_player(), index, pt);
  if (index != 0)
  {
    if (!make_move(state, pt, d2))
      return 0;
  }
  // did we play both our dice?
  if (index >= 2 || d1 == 0 || d2 == 0)
  {
    if (ai_next_player())
      play_turn(state); // if in search mode
    return 1;
  }
  // make another move
  if (index == 0)
  {
    SET(state->d1, 0);
  }
  else
  {
    SET(state->d2, 0);
  }
  return make_move_0(state);
}
Пример #14
0
void playsingle_controller::play_scenario_main_loop() {
	LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";


	// Avoid autosaving after loading, but still
	// allow the first turn to have an autosave.
	ai_testing::log_game_start();
	if(gamestate_.board_.teams().empty())
	{
		ERR_NG << "Playing game with 0 teams." << std::endl;
	}
	while(true) {
		play_turn();
		if (is_regular_game_end()) {
			return;
		}
		player_number_ = 1;
	} //end for loop
}
Пример #15
0
void play_game(const GameState* state)
{
  while (!is_game_over(state))
  {
    print_board(state);
    /*
    // AI solve for this player?
    if (ai_set_mode_search())
    {
      play_turn(state);
      ai_print_stats();
    }
    // commit the best move, or prompt human for move
    if (!ai_set_mode_play())
      break;
    */
    play_turn(state);
  }
}
void replay_controller::play_replay(){
	gui::button* b = gui_->find_button("button-stopreplay");
	if (b != NULL) { b->release(); }
	if (recorder.at_end()){
		return;
	}

	try{
		is_playing_ = true;

		DBG_REPLAY << "starting main loop\n" << (SDL_GetTicks() - ticks_) << "\n";
		for(; !recorder.at_end() && is_playing_; first_player_ = 1) {
			play_turn();
		} //end for loop
		is_playing_ = false;
	}
	catch(end_level_exception& e){
		if (e.result == QUIT) { throw e; }
	}
}
Пример #17
0
int run(void* foo, void* api, void* client_cx)
{
  init_game();
  set_event_handler(api, next_turn_callback);

  g_ccx = client_cx;
  while (get_state(api) != GS_END)
  {
    // Play a turn.
    // When this return, it means the user asked to go to
    // the next turn.
    play_turn();

    // Process our messages.
    process_messages(client_cx);
  }

  //end_game();
  foo = foo;
  return 0;
}
Пример #18
0
void playsingle_controller::play_scenario_main_loop()
{
	LOG_NG << "starting main loop\n" << (SDL_GetTicks() - ticks()) << "\n";


	// Avoid autosaving after loading, but still
	// allow the first turn to have an autosave.
	ai_testing::log_game_start();
	if(gamestate().board_.teams().empty())
	{
		ERR_NG << "Playing game with 0 teams." << std::endl;
	}
	while(true) {
		try {
			play_turn();
			if (is_regular_game_end()) {
				return;
			}
			gamestate_->player_number_ = 1;
		}
		catch(const reset_gamestate_exception& ex) {
			/**
				@TODO: The mp replay feature still doesnt work properly (casues OOS) becasue:
					1) The undo stack is not reset along with the gamestate (fixed).
					2) The server_request_number_ is not reset along with the gamestate (fixed).
					3) chat and other unsynced actions are inserted in the middle of the replay bringing the replay_pos in unorder (fixed).
					4) untracked changes in side controllers are lost when resetting gamestate.
					5) The game should have a stricter check for whether the loaded game is actually a parent of this game.
					6) If an action was undone after a game was saved it can casue if teh undone action is in the snapshot of the saved game. (luckyli this is never the case for autosaves)
			*/
			reset_gamestate(*ex.level, (*ex.level)["replay_pos"]);
			play_scenario_init(*ex.level);
			mp_replay_.reset(new replay_controller(*this, false, ex.level));
			mp_replay_->play_replay();
		}
	} //end for loop
}
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;
}
Пример #20
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;
}