示例#1
0
void playmp_controller::play_side(const unsigned int team_index, bool save)
{
	utils::string_map player;
	player["name"] = current_team().current_player();
	std::string turn_notification_msg = _("$name has taken control");
	turn_notification_msg = utils::interpolate_variables_into_string(turn_notification_msg, &player);
	gui_->send_notification(_("Turn changed"), turn_notification_msg);

	do {
		player_type_changed_ = false;
		if (!skip_next_turn_)
			end_turn_ = false;

		statistics::reset_turn_stats(teams_[team_index-1].save_id());

		// we can't call playsingle_controller::play_side because
		// we need to catch exception here
		if(current_team().is_human()) {
			LOG_NG << "is human...\n";


			try{
				play_ai_turn();
				before_human_turn(save);
				play_human_turn();
				after_human_turn();
			} catch(end_turn_exception& end_turn) {
				if (end_turn.redo == team_index) {
					player_type_changed_ = true;
					// if new controller is not human,
					// reset gui to prev human one
					if (!teams_[team_index-1].is_human()) {
						browse_ = true;
						int t = find_human_team_before(team_index);

						if (t <= 0)
							t = gui_->get_playing_team() + 1;

						gui_->set_team(t-1);
						gui_->recalculate_minimap();
						gui_->invalidate_all();
						gui_->draw(true,true);
					}
				} else {
					after_human_turn();
				}
			}
			LOG_NG << "human finished turn...\n";
		} else if(current_team().is_ai()) {
			play_ai_turn();
		} else if(current_team().is_network()) {
			play_network_turn();
		}
	} while (player_type_changed_);
	//keep looping if the type of a team (human/ai/networked) has changed mid-turn

	skip_next_turn_ = false;
}
void playsingle_controller::play_side(const unsigned int team_index, bool save)
{
	//check for team-specific items in the scenario
	gui_->parse_team_overlays();

	//flag used when we fallback from ai and give temporarily control to human
	do {
		// Although this flag is used only in this method,
		// it has to be a class member since derived classes
		// rely on it
		player_type_changed_ = false;
		if (!skip_next_turn_)
			end_turn_ = false;


		statistics::reset_turn_stats(teams_[team_index - 1].save_id());

		if (current_team().is_human()) {
			try {
				if (save) {
					play_ai_turn();
					if (tent::mode == TOWER_MODE) {
						do_fresh_heros(current_team(), false);
					}
				}
				before_human_turn(save);

				play_human_turn();
				after_human_turn();
			} catch(end_turn_exception& end_turn) {
				if (end_turn.redo == team_index) {
					player_type_changed_ = true;
					// If new controller is not human,
					// reset gui to prev human one
					if (!teams_[team_index-1].is_human()) {
						browse_ = true;
						int t = find_human_team_before(team_index);
						if (t > 0) {
							gui_->set_team(t-1);
							gui_->recalculate_minimap();
							gui_->invalidate_all();
							gui_->draw(true,true);
						}
					}
				}
			}
		} else if(current_team().is_ai()) {
			play_ai_turn();
		}
	} while (player_type_changed_);
	// Keep looping if the type of a team (human/ai/networked)
	// has changed mid-turn
	skip_next_turn_ = false;
}
void playsingle_controller::play_side(const unsigned int side_number, bool save)
{
	//check for team-specific items in the scenario
	gui_->parse_team_overlays();

	//flag used when we fallback from ai and give temporarily control to human
	bool temporary_human = false;
	do {
		// Although this flag is used only in this method,
		// it has to be a class member since derived classes
		// rely on it
		player_type_changed_ = false;
		if (!skip_next_turn_)
			end_turn_ = false;


		statistics::reset_turn_stats(teams_[side_number - 1].save_id());

		if(current_team().is_human() || temporary_human) {
			LOG_NG << "is human...\n";
			try{
				before_human_turn(save);
				play_human_turn();
				after_human_turn();
			} catch(end_turn_exception& end_turn) {
				if (end_turn.redo == side_number) {
					player_type_changed_ = true;
					// If new controller is not human,
					// reset gui to prev human one
					if (!teams_[side_number-1].is_human()) {
						browse_ = true;
						int t = find_human_team_before(side_number);
						if (t > 0) {
							update_gui_to_player(t-1);
						}
					}
				}
			}

			LOG_NG << "human finished turn...\n";
		} else if(current_team().is_ai()) {
			try {
				play_ai_turn();
			} catch(fallback_ai_to_human_exception&) {
				//give control to human for the rest of this turn
				player_type_changed_ = true;
				temporary_human = true;
			}
		}
	} while (player_type_changed_);
	// Keep looping if the type of a team (human/ai/networked)
	// has changed mid-turn
	skip_next_turn_ = false;
}
void playsingle_controller::play_side_impl()
{
	if (!skip_next_turn_) {
		end_turn_ = END_TURN_NONE;
	}
	if(replay_.get() != NULL) {
		REPLAY_RETURN res = replay_->play_side_impl();
		if(res == REPLAY_FOUND_END_TURN) {
			end_turn_ = END_TURN_SYNCED;
		}
		if (player_type_changed_) {
			replay_.reset();
		}
	} else if((current_team().is_local_human() && current_team().is_proxy_human())) {
		LOG_NG << "is human...\n";
		// If a side is dead end the turn, but play at least side=1's
		// turn in case all sides are dead
		if (gamestate().board_.side_units(current_side()) == 0 && !(gamestate().board_.units().size() == 0 && current_side() == 1)) {
			end_turn_ = END_TURN_REQUIRED;
		}

		before_human_turn();
		if (end_turn_ == END_TURN_NONE) {
			play_human_turn();
		}
		if ( !player_type_changed_ && !is_regular_game_end()) {
			after_human_turn();
		}
		LOG_NG << "human finished turn...\n";

	} else if(current_team().is_local_ai() || (current_team().is_local_human() && current_team().is_droid())) {
		play_ai_turn();
	} else if(current_team().is_network()) {
		play_network_turn();
	} else if(current_team().is_local_human() && current_team().is_idle()) {
		end_turn_enable(false);
		do_idle_notification();
		before_human_turn();
		if (end_turn_ == END_TURN_NONE) {
			play_idle_loop();
		}
	}
	else {
		// we should have skipped over empty controllers before so this shouldn't be possible
		ERR_NG << "Found invalid side controller " << current_team().controller().to_string() << " (" << current_team().proxy_controller().to_string() << ") for side " << current_team().side() << "\n";
	}
}
void playsingle_controller::play_side()
{
	//check for team-specific items in the scenario
	gui_->parse_team_overlays();

	maybe_do_init_side();
	if(is_regular_game_end()) {
		return;
	}
			
	//flag used when we fallback from ai and give temporarily control to human
	bool temporary_human = false;
	do {
		//Update viewing team in case it has changed during the loop.
		if(int side_num = play_controller::find_last_visible_team()) {
			if(side_num != this->gui_->viewing_side()) {
				update_gui_to_player(side_num - 1);
			}
		}
		// This flag can be set by derived classes (in overridden functions).
		player_type_changed_ = false;
		if (!skip_next_turn_)
			end_turn_ = END_TURN_NONE;

		statistics::reset_turn_stats(gamestate_.board_.teams()[player_number_ - 1].save_id());

		if((current_team().is_local_human() && current_team().is_proxy_human()) || temporary_human) {
			LOG_NG << "is human...\n";
			temporary_human = false;
			// If a side is dead end the turn, but play at least side=1's
			// turn in case all sides are dead
			if (gamestate_.board_.side_units(player_number_) == 0 && !(gamestate_.board_.units().size() == 0 && player_number_ == 1)) {
				end_turn_ = END_TURN_REQUIRED;
			}

			before_human_turn();
			if (end_turn_ == END_TURN_NONE) {
				play_human_turn();
			}
			if(is_regular_game_end()) {
				return;
			}
			if ( !player_type_changed_ ) {
				after_human_turn();
			}
			LOG_NG << "human finished turn...\n";

		} else if(current_team().is_local_ai() || (current_team().is_local_human() && current_team().is_droid())) {
			try {
				play_ai_turn();
			} catch(fallback_ai_to_human_exception&) {
				// Give control to a human for this turn.
				player_type_changed_ = true;
				temporary_human = true;
			}
			if(is_regular_game_end()) {
				return;
			}
		} else if(current_team().is_network()) {
			play_network_turn();
			if(is_regular_game_end()) {
				return;
			}
		} else if(current_team().is_local_human() && current_team().is_idle()) {
			end_turn_enable(false);
			do_idle_notification();
			before_human_turn();
			if (end_turn_ == END_TURN_NONE) {
				play_idle_loop();
				if(is_regular_game_end()) {
					return;
				}
			}
		}
		else {
			assert(current_team().is_empty()); // Do nothing.
		}

	} while (player_type_changed_);
	// Keep looping if the type of a team (human/ai/networked)
	// has changed mid-turn
	sync_end_turn();
	assert(end_turn_ == END_TURN_SYNCED);
	skip_next_turn_ = false;
}
示例#6
0
int main(int argc, char** argv) {
	int c;
    int errflg = 0, fflg = 0;
    char *ifile;
    extern char *optarg;
    extern int optind, optopt;

    ai_t ai = eval1_iter_ai; // the default ai, if none is specified
    int depth_cutoff = 30; 	// the default search depth cut-off

    turn_t ai_turn = white;	// the default first turn is white

	/* parse command line args */
	while ((c = getopt(argc, argv, "wbh12345d:f:")) != -1) {
        switch(c) {
        case 'w':
        	//AI white
        	ai_turn = white;
            printf("AI white - human black\n");
            break;
        case 'b':
        	//AI black
        	ai_turn = black;
            printf("human white - AI black\n");
            break;
        case '1':
        	// AI 1 - minimax
        	ai = minimax_ai;
            break;
        case '2':
        	// AI 2 - alpha-beta
        	ai = alphabeta_ai;
            break;
        case '3':
        	// AI 3 - iterative deepening alpha-beta
        	ai = ab_iter_ai;
            break;
        case '4':
        	// AI 4 - eval function 1
        	ai = eval1_ai;
            break;
        case '5':
        	// AI 5 - eval function 2
        	ai = eval1_iter_ai;
            break;
        case 'h':
        	//print help
        	errflg++;
        	break;
       	case 'd':
        	//depth cutoff
            depth_cutoff = atoi(optarg);
            if(depth_cutoff == 0) {
            	fprintf(stderr,
                    "depth cut-off must be a non-zero integer\n");
           		errflg++;
            }
            break;
        case 'f':
        	//input file
        	fflg++;
            ifile = optarg;
            break;
		case ':':       /* -f or -o without operand */
            fprintf(stderr,
                    "Option -%c requires an operand\n", optopt);
            errflg++;
            break;
        case '?':
            fprintf(stderr,
                	"Unrecognized option: -%c\n", optopt);
            errflg++;
        }
    }

    if (errflg) {
        printhelp();
        exit(2);
    }

    //if no input file set, set to default
    if (fflg == 0) {
    	ifile = DEFAULT_START;
    }

    //load starting position
    if(parsefile(ifile) != 0)
    	exit(1);

    // show the loaded state
    printf("starting position:\n");
	showstate(white_bits, black_bits);

	int result = 0;

	// check who starts
	if(ai_turn == white) {
		// AI starts
		printf("\nAI is white, AI starts.  Press any key to start AI turn.");
		
		getchar();	// wait for key to be pressed
		result = play_ai_turn(ai_turn, ai, &bitboard_white, bitboard_black, white_bits, black_bits, depth_cutoff);

		while(result == 0) {
			

			int bytes_read;
	  		int nbytes = 5;
	  		char *user_input = (char *) malloc (6);
	  		int inputerr = 1;
	  		int user_x, user_y, user_dir;

	  		printf("\nYour turn to move black:\n");

	  		while(inputerr != 0) {
	  			inputerr = 0;
		  		bytes_read = getline(&user_input, (size_t*)&nbytes, stdin);
		  		if(bytes_read == -1)
		  			inputerr++;
		  		user_x = (int)user_input[0] - 48;
		  		if(user_x < 1 || user_x > 7)
		  			inputerr++;
		  		user_y = (int)user_input[1] - 48;
		  		if(user_y < 1 || user_y > 7)
		  			inputerr++;
		  		switch(user_input[2]) {
		  		case 'N':
		  			user_dir = N;
		  			break;
		  		case 'E':
		  			user_dir = E;
		  			break;
		  		case 'W':
		  			user_dir = W;
		  			break;
		  		case 'S':
		  			user_dir = S;
		  			break;
		  		default:
		  			inputerr++;
		  		}
		  		if(inputerr) {
		  			printf("\nerror in input, try again:\n");
		  		} else {
		  			user_x = user_x - 1;
					user_y = user_y - 1;
					int bit_number = 8*user_y + user_x;
					uint64_t piece = (uint64_t)1 << bit_number;
					// make sure its a valid piece
					if(piece & bitboard_black) {
						int i = 0;
						while(piece != black_bits[i]){
							i++;
						}
		  				inputerr = trydir(user_dir, &piece, &bitboard_black, bitboard_white);
		  				if(inputerr == 0) {
		  					black_bits[i] = piece;
		  				}
		  			} else {
		  				inputerr++;
		  			}
		  			if(inputerr)
		  				printf("invalid move, try again:\n");
		  		}
		  	}

		  	showstate(white_bits, black_bits);
		  	printf("\nAI turn\n");
		  	result = play_ai_turn(ai_turn, ai, &bitboard_white, bitboard_black, white_bits, black_bits, depth_cutoff);
		}

	} else {
		// human starts, AI is black
		printf("AI is black, human starts.  Enter the first move to start.");

		while(result == 0) {

			int bytes_read;
	  		int nbytes = 5;
	  		char *user_input = (char *) malloc (nbytes + 1);

	  		int inputerr = 1;
	  		int user_x, user_y, user_dir;

	  		printf("\nYour turn to move white:\n");

	  		while(inputerr != 0) {
	  			inputerr = 0;
		  		bytes_read = getline(&user_input, (size_t*)&nbytes, stdin);
		  		if(bytes_read == -1)
		  			inputerr++;
		  		user_x = (int)user_input[0] - 48;
		  		if(user_x < 1 || user_x > 7)
		  			inputerr++;
		  		user_y = (int)user_input[1] - 48;
		  		if(user_y < 1 || user_y > 7)
		  			inputerr++;
		  		switch(user_input[2]) {
		  		case 'N':
		  			user_dir = N;
		  			break;
		  		case 'E':
		  			user_dir = E;
		  			break;
		  		case 'W':
		  			user_dir = W;
		  			break;
		  		case 'S':
		  			user_dir = S;
		  			break;
		  		default:
		  			inputerr++;
		  		}
		  		if(inputerr) {
		  			printf("\nerror in input, try again:\n");
		  		} else {
		  			user_x = user_x - 1;
					user_y = user_y - 1;
					int bit_number = 8*user_y + user_x;
					uint64_t piece = (uint64_t)1 << bit_number;
					// make sure its a valid piece
					if(piece & bitboard_white) {
						int i = 0;
						while(piece != white_bits[i]){
							i++;
						}
		  				inputerr = trydir(user_dir, &piece, &bitboard_white, bitboard_black);
		  				if(inputerr == 0) {
		  					white_bits[i] = piece;
		  				}
		  			} else {
		  				inputerr++;
		  			}
		  			if(inputerr)
		  				printf("invalid move, try again:\n");
		  		}
		  	}
		  	showstate(white_bits, black_bits);
			printf("\nAI turn\n");
			result = play_ai_turn(ai_turn, ai, &bitboard_black, bitboard_white, black_bits, white_bits, depth_cutoff);
		}
		
	}

	if(result == 1) {
		printf("\nAI wins!\n");
	} else {
		printf("\nThe winner is YOU!\n");
	}

	getchar();	

	return 0;
}
示例#7
0
possible_end_play_signal playsingle_controller::play_side()
{
    //check for team-specific items in the scenario
    gui_->parse_team_overlays();

    HANDLE_END_PLAY_SIGNAL( maybe_do_init_side(false) );

    //flag used when we fallback from ai and give temporarily control to human
    bool temporary_human = false;
    do {
        // This flag can be set by derived classes (in overridden functions).
        player_type_changed_ = false;
        if (!skip_next_turn_)
            end_turn_ = false;

        statistics::reset_turn_stats(gamestate_.board_.teams()[player_number_ - 1].save_id());

        if(current_team().is_human() || temporary_human) {
            LOG_NG << "is human...\n";
            temporary_human = false;
            // If a side is dead end the turn, but play at least side=1's
            // turn in case all sides are dead
            if (gamestate_.board_.side_units(player_number_) != 0
                    || (resources::units->size() == 0 && player_number_ == 1))
            {
                possible_end_play_signal signal = before_human_turn();

                if (!signal) {
                    signal = play_human_turn();
                }

                if (signal) {
                    switch (boost::apply_visitor(get_signal_type(), *signal)) {
                    case END_LEVEL:
                        return signal;
                    case END_TURN:
                        if (int(boost::apply_visitor(get_redo(),*signal)) == player_number_) {
                            player_type_changed_ = true;
                            // If new controller is not human,
                            // reset gui to prev human one
                            if (!gamestate_.board_.teams()[player_number_-1].is_human()) {
                                browse_ = true;
                                int s = find_human_team_before_current_player();
                                if (s <= 0)
                                    s = gui_->playing_side();
                                update_gui_to_player(s-1);
                            }
                        }

                    }
                }
            }

            // Ending the turn commits all moves.
            undo_stack_->clear();
            if ( !player_type_changed_ )
                after_human_turn();
            LOG_NG << "human finished turn...\n";

        } else if(current_team().is_ai()) {
            try {
                play_ai_turn();
            } catch(fallback_ai_to_human_exception&) {
                // Give control to a human for this turn.
                player_type_changed_ = true;
                temporary_human = true;
            } catch (end_level_exception & e) { //Don't know at the moment if these two are possible but can't hurt to add
                return possible_end_play_signal(e.to_struct());
            } catch (end_turn_exception & e) {
                return possible_end_play_signal(e.to_struct());
            }
            if(!player_type_changed_)
            {
                recorder.end_turn();
            }

        } else if(current_team().is_network()) {
            PROPOGATE_END_PLAY_SIGNAL( play_network_turn() );
        } else if(current_team().is_idle()) {
            end_turn_enable(false);
            do_idle_notification();

            possible_end_play_signal signal = before_human_turn();

            if (!signal) {
                signal = play_idle_loop();
            }

            if (signal) {
                switch (boost::apply_visitor(get_signal_type(), *signal)) {
                case END_LEVEL:
                    return signal;
                case END_TURN:
                    LOG_NG << "Escaped from idle state with exception!" << std::endl;
                    if (int(boost::apply_visitor(get_redo(), *signal)) == player_number_) {
                        player_type_changed_ = true;
                        // If new controller is not human,
                        // reset gui to prev human one
                        if (!gamestate_.board_.teams()[player_number_-1].is_human()) {
                            browse_ = true;
                            int s = find_human_team_before_current_player();
                            if (s <= 0)
                                s = gui_->playing_side();
                            update_gui_to_player(s-1);
                        }
                    }
                }
            }
        }

        // Else current_team().is_empty(), so do nothing.

    } while (player_type_changed_);
    // Keep looping if the type of a team (human/ai/networked)
    // has changed mid-turn
    skip_next_turn_ = false;
    return boost::none;
}
示例#8
0
void playsingle_controller::play_side(const unsigned int side_number, bool save)
{
	//check for team-specific items in the scenario
	gui_->parse_team_overlays();

	//flag used when we fallback from ai and give temporarily control to human
	bool temporary_human = false;
	do {
		// This flag can be set by derived classes (in overridden functions).
		player_type_changed_ = false;
		if (!skip_next_turn_)
			end_turn_ = false;

		statistics::reset_turn_stats(teams_[side_number - 1].save_id());

		if(current_team().is_human() || temporary_human) {
			LOG_NG << "is human...\n";
			temporary_human = false;
			try{
				before_human_turn(save);
				play_human_turn();
			} catch(end_turn_exception& end_turn) {
				if (end_turn.redo == side_number) {
					player_type_changed_ = true;
					// If new controller is not human,
					// reset gui to prev human one
					if (!teams_[side_number-1].is_human()) {
						browse_ = true;
						int s = find_human_team_before(side_number);
						if (s <= 0)
							s = gui_->playing_side();
						update_gui_to_player(s-1);
					}
				}
			}
			// Ending the turn commits all moves.
			undo_stack_->clear();
			if ( !player_type_changed_ )
				after_human_turn();
			LOG_NG << "human finished turn...\n";

		} else if(current_team().is_ai()) {
			try {
				play_ai_turn();
			} catch(fallback_ai_to_human_exception&) {
				// Give control to a human for this turn.
				player_type_changed_ = true;
				temporary_human = true;
			}

		} else if(current_team().is_network()) {
			play_network_turn();
		}

		// Else current_team().is_empty(), so do nothing.

	} while (player_type_changed_);
	// Keep looping if the type of a team (human/ai/networked)
	// has changed mid-turn
	skip_next_turn_ = false;
}
void playsingle_controller::play_side()
{
	//check for team-specific items in the scenario
	gui_->parse_team_overlays();

	int end_ticks = calculate_end_ticks();
	while (unit_map::main_ticks < end_ticks && !player_type_changed_) {
		VALIDATE(!unit::actor, "playsingle_controller::play_side, unit::actor isn't NULL!");

		unit* u = &units_.current_unit();
		if (!tent::turn_based) {
			int past_ticks = u->backward_ticks(u->ticks());
			if (unit_map::main_ticks + past_ticks >= end_ticks) {
				units_.do_escape_ticks_uh(teams_, *gui_, end_ticks - unit_map::main_ticks, false);
				autosave_ticks_ = -1;
				continue;
			}
			u = NULL;
			units_.do_escape_ticks_uh(teams_, *gui_, past_ticks, true);
		} else {
			if (u->side() < player_number_) {
				unit_map::main_ticks = end_ticks;
				player_number_ = 1;
				continue;
			}
		}
		
		bool new_side = do_prefix_unit(end_ticks, loading_game_, true);

		if (actor_can_continue_action(units_, player_number_)) {
			team& t = teams_[player_number_ - 1];
			// Although this flag is used only in this method,
			// it has to be a class member since derived classes
			// rely on it
			player_type_changed_ = false;
			if (!skip_next_turn_) {
				end_turn_ = false;
			}

			if (t.is_human()) {
				try {
					if (!loading_game_ && unit::actor->human_team_can_ai()) {
						play_ai_turn(NULL);
					}
					before_human_turn(new_side);
					play_human_turn();
					after_human_turn();

				} catch(end_turn_exception& end_turn) {
					if (end_turn.redo == player_number_ - 1) {
						player_type_changed_ = true;
						// If new controller is not human,
						// reset gui to prev human one
						if (!teams_[player_number_ - 2].is_human()) {
							browse_ = true;
							int t = find_human_team_before(player_number_ - 1);
							if (t > 0) {
								gui_->set_team(t-1);
								gui_->recalculate_minimap();
								gui_->invalidate_all();
								gui_->draw(true,true);
							}
						}
					}
				}
			} else if (t.is_ai()) {
				play_ai_turn(NULL);

			}
		}

		do_post_unit(false);

		if (!gui_->access_is_null(game_display::taccess_list::TROOP)) {
			gui_->verify_access_troops();
		}
		
		loading_game_ = false;
	}
	// Keep looping if the type of a team (human/ai/networked)
	// has changed mid-turn
	skip_next_turn_ = false;
}
示例#10
0
void playmp_controller::play_side()
{
	utils::string_map player;
	player["name"] = current_team().current_player();
	std::string turn_notification_msg = _("$name has taken control");
	turn_notification_msg = utils::interpolate_variables_into_string(turn_notification_msg, &player);
	gui_->send_notification(_("Turn changed"), turn_notification_msg);

	int end_ticks = calculate_end_ticks();

	player_type_changed_ = false;
	while (unit_map::main_ticks < end_ticks && !player_type_changed_) {
		VALIDATE(!unit::actor, "playmp_controller::play_side, unit::actor isn't NULL!");

		if (!skip_next_turn_) {
			end_turn_ = false;
		}

		unit* u = &units_.current_unit();
		if (!tent::turn_based) {
			int past_ticks = u->backward_ticks(u->ticks());
			if (unit_map::main_ticks + past_ticks >= end_ticks) {
				units_.do_escape_ticks_uh(teams_, *gui_, end_ticks - unit_map::main_ticks, false);
				autosave_ticks_ = -1;
				continue;
			}
			units_.do_escape_ticks_uh(teams_, *gui_, past_ticks, true);
		} else {
			if (u->side() < player_number_) {
				unit_map::main_ticks = end_ticks;
				player_number_ = 1;
				continue;
			}
		}
		// if exist spirit feature/technology, second maybe goto first. need reget
		u = &units_.current_unit();

		player_number_ = u->side(); // init_turn_data need player_number_ be valid.
		team& t = teams_[player_number_ - 1];

		bool local = t.is_local();
		bool new_side = false;
		if (local || loading_game_) {
			if (local) {
				init_turn_data();
			}
			new_side = do_prefix_unit(end_ticks, loading_game_, false);
		}

		if (t.is_network()) {
			play_network_turn();

		} else if (actor_can_continue_action(units_, player_number_)) {
			// we can't call playsingle_controller::play_side because
			// we need to catch exception here
			if (t.is_human()) {
				try {
					if (!loading_game_ && unit::actor->human_team_can_ai()) {
						play_ai_turn(turn_data_);
					}
					before_human_turn(new_side);
					play_human_turn();
					after_human_turn();
				} catch (end_turn_exception& end_turn) {
					if (end_turn.redo == player_number_ - 1) {
						player_type_changed_ = true;
						// if new controller is not human,
						// reset gui to prev human one
						if (!teams_[player_number_ - 2].is_human()) {
							browse_ = true;
							int t = find_human_team_before(player_number_ - 1);

							if (t <= 0)
								t = gui_->get_playing_team() + 1;

							gui_->set_team(t-1);
							gui_->recalculate_minimap();
							gui_->invalidate_all();
							gui_->draw(true,true);
						}
					} else {
						after_human_turn();
					}
				}

			} else if (t.is_ai()) {
				play_ai_turn(turn_data_);

			}
		}

		if (local) {
			do_post_unit(false);
			release_turn_data();
		}

		loading_game_ = false;
	}
	//keep looping if the type of a team (human/ai/networked) has changed mid-turn

	skip_next_turn_ = false;
}