void play_controller::finish_side_turn() { whiteboard_manager_->on_finish_side_turn(current_side()); { //Block for set_scontext_synced set_scontext_synced sync(1); // Ending the turn commits all moves. undo_stack().clear(); gamestate().board_.end_turn(current_side()); const std::string turn_num = std::to_string(turn()); const std::string side_num = std::to_string(current_side()); // Clear shroud, in case units had been slowed for the turn. actions::clear_shroud(current_side()); pump().fire("side_turn_end"); pump().fire("side_"+ side_num + "_turn_end"); pump().fire("side_turn_" + turn_num + "_end"); pump().fire("side_" + side_num + "_turn_" + turn_num + "_end"); // This is where we refog, after all of a side's events are done. actions::recalculate_fog(current_side()); check_victory(); sync.do_final_checkup(); } mouse_handler_.deselect_hex(); resources::gameboard->unit_id_manager().reset_fake(); gamestate_->init_side_done() = false; }
int play_controller::find_last_visible_team() const { assert(current_side() <= int(gamestate().board_.teams().size())); const int num_teams = gamestate().board_.teams().size(); const bool is_observer = this->is_observer(); for(int i = 0; i < num_teams; i++) { const int team_num = modulo(current_side() - i, num_teams, 1); if(is_team_visible(team_num, is_observer)) { return team_num; } } return 0; }
void play_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(gui_->video().non_interactive()) { LOG_AIT << "Turn " << turn() << ":" << std::endl; } for (; gamestate_->player_number_ <= int(gamestate().board_.teams().size()); ++gamestate_->player_number_) { // If a side is empty skip over it. if (current_team().is_empty()) { continue; } init_side_begin(); if(gamestate_->init_side_done()) { // This is the case in a reloaded game where the side was initialized before saving the game. init_side_end(); } ai_testing::log_turn_start(current_side()); play_side(); if(is_regular_game_end()) { return; } finish_side_turn(); if(is_regular_game_end()) { return; } if(gui_->video().non_interactive()) { LOG_AIT << " Player " << current_side() << ": " << current_team().villages().size() << " Villages" << std::endl; ai_testing::log_turn_end(current_side()); } } // If the loop exits due to the last team having been processed. gamestate_->player_number_ = gamestate().board_.teams().size(); finish_turn(); // Time has run out check_time_over(); }
void play_controller::init_side_begin() { mouse_handler_.set_side(current_side()); // If we are observers we move to watch next team if it is allowed if ((is_observer() && !current_team().get_disallow_observers()) || (current_team().is_local_human() && !this->is_replay())) { update_gui_to_player(current_side() - 1); } gui_->set_playing_team(size_t(current_side() - 1)); gamestate().gamedata_.last_selected = map_location::null_location(); }
void play_controller::init_side_end() { const time_of_day& tod = gamestate().tod_manager_.get_time_of_day(); if (current_side() == 1 || !init_side_done_now_) sound::play_sound(tod.sounds, sound::SOUND_SOURCES); if (!is_skipping_replay()) { gui_->invalidate_all(); } if (!is_skipping_replay() && current_team().get_scroll_to_leader()) { gui_->scroll_to_leader(current_side(), game_display::ONSCREEN,false); } whiteboard_manager_->on_init_side(); }
void play_controller::enter_textbox() { if(menu_handler_.get_textbox().active() == false) { return; } const std::string str = menu_handler_.get_textbox().box()->text(); const unsigned int team_num = current_side(); events::mouse_handler& mousehandler = mouse_handler_; switch(menu_handler_.get_textbox().mode()) { case gui::TEXTBOX_SEARCH: menu_handler_.do_search(str); menu_handler_.get_textbox().close(*gui_); break; case gui::TEXTBOX_MESSAGE: menu_handler_.do_speak(); menu_handler_.get_textbox().close(*gui_); //need to close that one after executing do_speak() ! break; case gui::TEXTBOX_COMMAND: menu_handler_.get_textbox().close(*gui_); menu_handler_.do_command(str); break; case gui::TEXTBOX_AI: menu_handler_.get_textbox().close(*gui_); menu_handler_.do_ai_formula(str, team_num, mousehandler); break; default: menu_handler_.get_textbox().close(*gui_); ERR_DP << "unknown textbox mode" << std::endl; } }
void playsingle_controller::end_turn(){ if (linger_) end_turn_ = END_TURN_REQUIRED; else if (!is_browsing() && menu_handler_.end_turn(current_side())){ end_turn_ = END_TURN_REQUIRED; } }
void play_controller::play_side() { //check for team-specific items in the scenario gui_->parse_team_overlays(); do { update_viewing_player(); { save_blocker blocker; maybe_do_init_side(); if(is_regular_game_end()) { return; } } // This flag can be set by derived classes (in overridden functions). player_type_changed_ = false; statistics::reset_turn_stats(gamestate().board_.teams()[current_side() - 1].save_id()); play_side_impl(); if(is_regular_game_end()) { return; } } while (player_type_changed_); // Keep looping if the type of a team (human/ai/networked) // has changed mid-turn sync_end_turn(); }
void play_controller::process_keyup_event(const SDL_Event& event) { // If the user has pressed 1 through 9, we want to show // how far the unit can move in that many turns if(event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9') { const int new_path_turns = (event.type == SDL_KEYDOWN) ? event.key.keysym.sym - '1' : 0; if(new_path_turns != mouse_handler_.get_path_turns()) { mouse_handler_.set_path_turns(new_path_turns); const unit_map::iterator u = mouse_handler_.selected_unit(); if(u.valid()) { // if it's not the unit's turn, we reset its moves unit_movement_resetter move_reset(*u, u->side() != current_side()); mouse_handler_.set_current_paths(pathfind::paths(*u, false, true, gamestate().board_.teams_[gui_->viewing_team()], mouse_handler_.get_path_turns())); gui_->highlight_reach(mouse_handler_.current_paths()); } else { mouse_handler_.select_hex(mouse_handler_.get_selected_hex(), false, false, false); } } } else if (event.key.keysym.sym == SDLK_TAB) { static CKey keys; if (!keys[SDLK_TAB]) { whiteboard_manager_->set_invert_behavior(false); } } }
void playsingle_controller::show_turn_dialog(){ if(preferences::turn_dialog() && !is_regular_game_end() ) { blindfold b(*gui_, true); //apply a blindfold for the duration of this dialog gui_->redraw_everything(); gui_->recalculate_minimap(); std::string message = _("It is now $name|’s turn"); utils::string_map symbols; symbols["name"] = gamestate().board_.teams()[current_side() - 1].side_name(); message = utils::interpolate_variables_into_string(message, &symbols); gui2::show_transient_message(gui_->video(), "", message); } }
void playsingle_controller::execute_gotos() { if(should_return_to_play_side()) { return; } try { menu_handler_.execute_gotos(mouse_handler_, current_side()); } catch (const return_to_play_side_exception&) { } }
void playsingle_controller::play_ai_turn() { LOG_NG << "is ai...\n"; end_turn_enable(false); gui_->recalculate_minimap(); const cursor::setter cursor_setter(cursor::WAIT); // Correct an oddball case where a human could have left delayed shroud // updates on before giving control to the AI. (The AI does not bother // with the undo stack, so it cannot delay shroud updates.) team & cur_team = current_team(); if ( !cur_team.auto_shroud_updates() ) { // We just took control, so the undo stack is empty. We still need // to record this change for the replay though. synced_context::run_and_store("auto_shroud", replay_helper::get_auto_shroud(true)); } undo_stack().clear(); turn_data_.send_data(); try { try { if (!should_return_to_play_side()) { ai::manager::play_turn(current_side()); } } catch (return_to_play_side_exception&) { } catch (fallback_ai_to_human_exception&) { current_team().make_human(); player_type_changed_ = true; } } catch(...) { turn_data_.sync_network(); throw; } if(!should_return_to_play_side()) { end_turn_ = END_TURN_REQUIRED; } turn_data_.sync_network(); gui_->recalculate_minimap(); gui_->invalidate_unit(); gui_->invalidate_game_status(); gui_->invalidate_all(); gui_->draw(); }
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 playmp_controller::after_human_turn(){ if(saved_game_.mp_settings().mp_countdown) { //time_left + turn_bonus + (action_bonus * number of actions done) const int new_time_in_secs = (current_team().countdown_time() / 1000) + saved_game_.mp_settings().mp_countdown_turn_bonus + saved_game_.mp_settings().mp_countdown_action_bonus * current_team().action_bonus_count(); const int new_time = 1000 * std::min<int>(new_time_in_secs, saved_game_.mp_settings().mp_countdown_reservoir_time); current_team().set_action_bonus_count(0); current_team().set_countdown_time(new_time); resources::recorder->add_countdown_update(new_time, current_side()); } LOG_NG << "playmp::after_human_turn...\n"; // Normal post-processing for human turns (clear undos, end the turn, etc.) playsingle_controller::after_human_turn(); //send one more time to make sure network is up-to-date. turn_data_.send_data(); }
network::connection current_player() const { return (nsides_ ? sides_[current_side()] : 0); }
void play_controller::do_init_side() { set_scontext_synced sync; log_scope("player turn"); // In case we might end up calling sync:network during the side turn events, // and we don't want do_init_side to be called when a player drops. gamestate_->init_side_done() = true; init_side_done_now_ = true; const std::string turn_num = std::to_string(turn()); const std::string side_num = std::to_string(current_side()); gamestate().gamedata_.get_variable("side_number") = current_side(); // We might have skipped some sides because they were empty so it is not enough to check for side_num==1 if(!gamestate().tod_manager_.has_turn_event_fired()) { pump().fire("turn_" + turn_num); pump().fire("new_turn"); gamestate().tod_manager_.turn_event_fired(); } pump().fire("side_turn"); pump().fire("side_" + side_num + "_turn"); pump().fire("side_turn_" + turn_num); pump().fire("side_" + side_num + "_turn_" + turn_num); // We want to work out if units for this player should get healed, // and the player should get income now. // Healing/income happen if it's not the first turn of processing, // or if we are loading a game. if (turn() > 1) { gamestate().board_.new_turn(current_side()); current_team().new_turn(); // If the expense is less than the number of villages owned // times the village support capacity, // then we don't have to pay anything at all int expense = gamestate().board_.side_upkeep(current_side()) - current_team().support(); if(expense > 0) { current_team().spend_gold(expense); } calculate_healing(current_side(), !is_skipping_replay()); } // Prepare the undo stack. undo_stack().new_side_turn(current_side()); pump().fire("turn_refresh"); pump().fire("side_" + side_num + "_turn_refresh"); pump().fire("turn_" + turn_num + "_refresh"); pump().fire("side_" + side_num + "_turn_" + turn_num + "_refresh"); // Make sure vision is accurate. actions::clear_shroud(current_side(), true); init_side_end(); check_victory(); sync.do_final_checkup(); }
const team& play_controller::current_team() const { assert(current_side() > 0 && current_side() <= int(gamestate().board_.teams().size())); return gamestate().board_.teams()[current_side() - 1]; }