예제 #1
0
possible_end_play_signal playmp_controller::play_idle_loop()
{
	LOG_NG << "playmp::play_human_turn...\n";

	remove_blindfold();

	while (!end_turn_)
	{
		turn_info_send send_safe(turn_data_);
		config cfg;
		if(network_reader_.read(cfg)) {
			turn_info::PROCESS_DATA_RESULT res;
			HANDLE_END_PLAY_SIGNAL( res = turn_data_.process_network_data(cfg, skip_replay_) );

			if (res == turn_info::PROCESS_RESTART_TURN || res == turn_info::PROCESS_RESTART_TURN_TEMPORARY_LOCAL)
			{
				end_turn_struct ets = {static_cast<unsigned>(gui_->playing_side())};
				return possible_end_play_signal(ets);
				//throw end_turn_exception(gui_->playing_side());
			}
		}

		HANDLE_END_PLAY_SIGNAL ( play_slice() );
		HANDLE_END_PLAY_SIGNAL ( check_end_level() );

		if (!linger_) {
			SDL_Delay(1);
		}

		gui_->draw();
	}
	return boost::none;
}
예제 #2
0
possible_end_play_signal playmp_controller::play_network_turn(){
	LOG_NG << "is networked...\n";

	end_turn_enable(false);
	turn_data_.send_data();

	for(;;) {

		if (!network_processing_stopped_){
			config cfg;
			if(network_reader_.read(cfg)) {
				if (replay_last_turn_ <= turn()){
					if (skip_replay_) {
						skip_replay_ = false;
					}
				}
				turn_info::PROCESS_DATA_RESULT result;
				HANDLE_END_PLAY_SIGNAL ( result = turn_data_.process_network_data(cfg, skip_replay_) );
				if(player_type_changed_ == true)
				{
					//we received a player change/quit during waiting in get_user_choice/synced_context::pull_remote_user_input
					return boost::none;
				}
				if (result == turn_info::PROCESS_RESTART_TURN || result == turn_info::PROCESS_RESTART_TURN_TEMPORARY_LOCAL) {
					player_type_changed_ = true;
					return boost::none;
				} else if (result == turn_info::PROCESS_END_TURN) {
					break;
				}
			}
			/*
				we might have data left in replay that we recieved during prestart events. (or maybe other events.)
			*/
			else if(!recorder.at_end())
			{
				bool was_skipping = recorder.is_skipping();
				recorder.set_skip(skip_replay_);
				if(do_replay() == REPLAY_FOUND_END_TURN)
				{
					break;
				}
				recorder.set_skip(was_skipping);
			}
		}

		HANDLE_END_PLAY_SIGNAL( play_slice() );
		HANDLE_END_PLAY_SIGNAL( check_end_level() );

		if (!network_processing_stopped_){
			turn_data_.send_data();
		}

		gui_->draw();
	}

	LOG_NG << "finished networked...\n";
	return boost::none;
}
예제 #3
0
possible_end_play_signal playsingle_controller::play_human_turn() {
    show_turn_dialog();
    HANDLE_END_PLAY_SIGNAL( execute_gotos() );

    end_turn_enable(true);
    while(!end_turn_) {
        HANDLE_END_PLAY_SIGNAL( play_slice() );
        HANDLE_END_PLAY_SIGNAL( check_end_level() );
        gui_->draw();
    }

    return boost::none;
}
예제 #4
0
possible_end_play_signal playsingle_controller::check_time_over() {
    bool b = gamestate_.tod_manager_.next_turn(*resources::gamedata);
    it_is_a_new_turn_ = true;
    if(!b) {

        LOG_NG << "firing time over event...\n";
        game_events::fire("time over");
        LOG_NG << "done firing time over event...\n";
        //if turns are added while handling 'time over' event
        if (gamestate_.tod_manager_.is_time_left()) {
            return boost::none;
        }

        if(non_interactive()) {
            LOG_AIT << "time over (draw)\n";
            ai_testing::log_draw();
        }

        HANDLE_END_PLAY_SIGNAL( check_victory() );

        get_end_level_data().proceed_to_next_level = false;

        end_level_struct els = {DEFEAT};
        return possible_end_play_signal (els);
        //throw end_level_exception(DEFEAT);
    }
    return boost::none;
}
possible_end_play_signal replay_controller::replay_next_side(){
	is_playing_ = true;
	replay_ui_playback_should_start();

	HANDLE_END_PLAY_SIGNAL( play_side() );
	while (current_team().is_empty()) {
		HANDLE_END_PLAY_SIGNAL( play_side() );
	}

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

	replay_ui_playback_should_stop();
	return boost::none;
}
예제 #6
0
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;
}
예제 #7
0
possible_end_play_signal playsingle_controller::play_idle_loop()
{
    while(!end_turn_) {
        HANDLE_END_PLAY_SIGNAL( play_slice() );
        gui_->draw();
        SDL_Delay(10);
    }
    return boost::none;
}
possible_end_play_signal play_replay_level_main_loop(replay_controller & replaycontroller, bool & is_unit_test) {
	if (is_unit_test) {
		return replaycontroller.try_run_to_completion();
	}

	for (;;){
		HANDLE_END_PLAY_SIGNAL( replaycontroller.play_slice() );
	}
}
possible_end_play_signal replay_controller::try_run_to_completion() {
	for (;;) {
		HANDLE_END_PLAY_SIGNAL( play_slice() );
		if (recorder.at_end()) {
			return boost::none;
		} else {
			if (!is_playing_) {
				PROPOGATE_END_PLAY_SIGNAL( play_replay() );
			}
		}
	}
}
//make all sides move, then stop
possible_end_play_signal replay_controller::play_turn(){

	LOG_REPLAY << "turn: " << current_turn_ << "\n";

	gui_->new_turn();
	gui_->invalidate_game_status();
	events::raise_draw_event();

	bool last_team = false;

	while ( (!last_team) && (!recorder.at_end()) && is_playing_ ){
		last_team = static_cast<size_t>(player_number_) == gamestate_.board_.teams().size();
		PROPOGATE_END_PLAY_SIGNAL( play_side() );
		HANDLE_END_PLAY_SIGNAL( play_slice() );
	}
	return boost::none;
}
예제 #11
0
possible_end_play_signal playsingle_controller::before_human_turn()
{
    log_scope("player turn");
    browse_ = false;
    linger_ = false;

    HANDLE_END_PLAY_SIGNAL( ai::manager::raise_turn_started() ); //This line throws exception from here: https://github.com/wesnoth/wesnoth/blob/ac96a2b91b3276e20b682210617cf87d1e0d366a/src/playsingle_controller.cpp#L954

    if(do_autosaves_ && level_result_ == NONE) {
        savegame::autosave_savegame save(saved_game_, *gui_, to_config(), preferences::save_compression_format());
        save.autosave(game_config::disable_autosave, preferences::autosavemax(), preferences::INFINITE_AUTO_SAVES);
    }

    if(preferences::turn_bell() && level_result_ == NONE) {
        sound::play_bell(game_config::sounds::turn_bell);
    }
    return boost::none;
}
예제 #12
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;
}
예제 #13
0
possible_end_play_signal playsingle_controller::play_turn()
{
    whiteboard_manager_->on_gamestate_change();
    gui_->new_turn();
    gui_->invalidate_game_status();
    events::raise_draw_event();

    LOG_NG << "turn: " << turn() << "\n";

    if(non_interactive()) {
        LOG_AIT << "Turn " << turn() << ":" << std::endl;
    }

    for (player_number_ = first_player_; player_number_ <= int(gamestate_.board_.teams().size()); ++player_number_)
    {
        // If a side is empty skip over it.
        if (current_team().is_empty()) continue;

        possible_end_play_signal signal;
        {
            save_blocker blocker;
            signal = init_side();
        }

        if (signal) {
            switch (boost::apply_visitor(get_signal_type(), *signal)) {
            case END_TURN:
                if (current_team().is_network() == false) {
                    turn_data_.send_data();
                    recorder.end_turn();
                    turn_data_.sync_network();
                }
                continue;
            case END_LEVEL:
                return signal;
            }
        }

        if (replaying_) {
            LOG_NG << "doing replay " << player_number_ << "\n";
            HANDLE_END_PLAY_SIGNAL ( replaying_ = ::do_replay() == REPLAY_FOUND_END_TURN );
            LOG_NG << "result of replay: " << (replaying_?"true":"false") << "\n";
        } else {
            ai_testing::log_turn_start(player_number_);
            PROPOGATE_END_PLAY_SIGNAL ( play_side() );
        }

        finish_side_turn();

        if(non_interactive()) {
            LOG_AIT << " Player " << player_number_ << ": " <<
                    current_team().villages().size() << " Villages" <<
                    std::endl;
            ai_testing::log_turn_end(player_number_);
        }

        HANDLE_END_PLAY_SIGNAL ( check_victory() );

        //if loading a savegame, network turns might not have reset this yet
        loading_game_ = false;
    }
    //If the loop exits due to the last team having been processed,
    //player_number_ will be 1 too high
    if(player_number_ > static_cast<int>(gamestate_.board_.teams().size()))
        player_number_ = gamestate_.board_.teams().size();

    finish_turn();

    // Time has run out
    PROPOGATE_END_PLAY_SIGNAL ( check_time_over() );
    return boost::none;
}
예제 #14
0
possible_end_play_signal playmp_controller::play_human_turn(){
	LOG_NG << "playmp::play_human_turn...\n";

	remove_blindfold();
	int cur_ticks = SDL_GetTicks();
	show_turn_dialog();

	if (!preferences::disable_auto_moves()) {
		HANDLE_END_PLAY_SIGNAL(execute_gotos());
	}

	if (!linger_ || is_host()) {
		end_turn_enable(true);
	}
	while(!end_turn_) {
		turn_info_send send_safe(turn_data_);
			config cfg;

			if(network_reader_.read(cfg)) {
				turn_info::PROCESS_DATA_RESULT res;
				HANDLE_END_PLAY_SIGNAL( res = turn_data_.process_network_data(cfg, skip_replay_) );
				//PROCESS_RESTART_TURN_TEMPORARY_LOCAL should be impossible because that's means the currently active side (that's us) left.
				if (res == turn_info::PROCESS_RESTART_TURN || res == turn_info::PROCESS_RESTART_TURN_TEMPORARY_LOCAL)
				{
					// Clean undo stack if turn has to be restarted (losing control)
					if ( undo_stack_->can_undo() )
					{
						font::floating_label flabel(_("Undoing moves not yet transmitted to the server."));

						SDL_Color color = {255,255,255,255};
						flabel.set_color(color);
						SDL_Rect rect = gui_->map_area();
						flabel.set_position(rect.w/2, rect.h/2);
						flabel.set_lifetime(150);
						flabel.set_clip_rect(rect);

						font::add_floating_label(flabel);
					}

					while( undo_stack_->can_undo() )
						undo_stack_->undo();

					end_turn_struct ets = {static_cast<unsigned>(gui_->playing_side())};
					return possible_end_play_signal(ets);
					//throw end_turn_exception(gui_->playing_side());
				}
				else if(res == turn_info::PROCESS_END_LINGER)
				{
					if(!linger_)
						replay::process_error("Received unexpected next_scenario durign the game");
					else
					{
						//we end the turn immidiately to prevent receiving data of the next scenario while we are not playing it.
						end_turn();
					}
				}
			}

			HANDLE_END_PLAY_SIGNAL( play_slice() );
			HANDLE_END_PLAY_SIGNAL( check_end_level() );

		if (!linger_ && (current_team().countdown_time() > 0) && saved_game_.mp_settings().mp_countdown) {
			SDL_Delay(1);
			const int ticks = SDL_GetTicks();
			int new_time = current_team().countdown_time()-std::max<int>(1,(ticks - cur_ticks));
			if (new_time > 0 ){
				current_team().set_countdown_time(new_time);
				cur_ticks = ticks;
				if(current_team().is_human() && !beep_warning_time_) {
					beep_warning_time_ = new_time - WARNTIME + ticks;
				}
				if(counting_down()) {
					think_about_countdown(ticks);
				}
			} else {
				// Clock time ended
				// If no turn bonus or action bonus -> defeat
				const int action_increment = saved_game_.mp_settings().mp_countdown_action_bonus;
				if ( (saved_game_.mp_settings().mp_countdown_turn_bonus == 0 )
					&& (action_increment == 0 || current_team().action_bonus_count() == 0)) {
					// Not possible to end level in MP with throw end_level_exception(DEFEAT);
					// because remote players only notice network disconnection
					// Current solution end remaining turns automatically
					current_team().set_countdown_time(10);
				}

				return possible_end_play_signal(end_turn_exception().to_struct());
				//throw end_turn_exception();
			}
		}

		gui_->draw();
	}
	return boost::none;
}