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; }
void play_controller::reset_gamestate(const config& level, int replay_pos) { resources::gameboard = nullptr; resources::gamedata = nullptr; resources::tod_manager = nullptr; resources::units = nullptr; resources::filter_con = nullptr; resources::lua_kernel = nullptr; resources::game_events = nullptr; resources::tunnels = nullptr; resources::undo_stack = nullptr; gui_->labels().set_team(nullptr); gamestate_.reset(new game_state(level, *this, tdata_)); resources::gameboard = &gamestate().board_; resources::gamedata = &gamestate().gamedata_; resources::tod_manager = &gamestate().tod_manager_; resources::units = &gamestate().board_.units_; resources::filter_con = &gamestate(); resources::undo_stack = &undo_stack(); resources::game_events = gamestate().events_manager_.get(); resources::lua_kernel = gamestate().lua_kernel_.get(); gamestate_->init(level, *this); gamestate().set_game_display(gui_.get()); resources::tunnels = gamestate().pathfind_manager_.get(); gui_->reset_tod_manager(gamestate().tod_manager_); gui_->reset_reports(*gamestate().reports_); gui_->change_display_context(&gamestate().board_); saved_game_.get_replay().set_pos(replay_pos); gamestate().gamedata_.set_phase(game_data::PRELOAD); gamestate().lua_kernel_->load_game(level); }
void playmp_controller::send_user_choice() { // when using a remote user choice undoing must be impossible because that network traffic cannot be undone // Also turn_data_.send_data() won't work if the undo stack isn't empty because undoable moves won't be sended // Also undo_stack()clear() must be called synced so we cannot do that here. assert(!undo_stack().can_undo()); turn_data_.send_data(); }
void playmp_controller::pull_remote_choice() { // when using a remote user choice undoing must be impossible because that network traffic cannot be undone // Also turn_data_.sync_network() (which calls turn_data_.send_data()) won't work if the undo stack isn't empty because undoable moves won't be sended // Also undo_stack()clear() must be called synced so we cannot do that here. assert(!undo_stack().can_undo()); turn_info::PROCESS_DATA_RESULT res = turn_data_.sync_network(); assert(res != turn_info::PROCESS_END_LINGER); assert(res != turn_info::PROCESS_END_TURN); if(res == turn_info::PROCESS_RESTART_TURN) { player_type_changed_ = true; } }
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 GameView::dropEvent(QDropEvent *event) { if (my_world == nullptr) { return; } if (event->mimeData()->hasFormat("mm/object")) { log_debug(DEBUG_EDITOR, "Drop accepted"); const QMimeData *mime_data = event->mimeData(); if (mime_data->hasFormat("mm/object")) { event->acceptProposedAction(); QString object_type(mime_data->data("mm/object")); log_debug(DEBUG_EDITOR, "Drop event %s", object_type.toLatin1().data()); bool ok = false; u32 index = object_type.toLatin1().toInt(&ok); if (index >= application().core().entity_creators().size()) { log_warning("Invalid object index %i, max index is %i", index, application().core().entity_creators().size()); return; } if (!ok) { return; } sptr<Entity> entity = application().core().entity_creators()[index].create(*my_world, application().core()); if (entity != nullptr) { entity->set_class_name(application().core().entity_creators()[index].name); log_info("Adding entity to the world"); EntityAdd *command = new EntityAdd(entity, application().world()); undo_stack().push(command); } else { log_warning("Error while creating object"); } } else { log_debug(DEBUG_EDITOR, "Drop ignored"); event->ignore(); } } }
void playmp_controller::surrender(int side_number) { undo_stack().clear(); resources::recorder->add_surrender(side_number); turn_data_.send_data(); }
void playmp_controller::play_human_turn() { LOG_NG << "playmp::play_human_turn...\n"; assert(!linger_); assert(gamestate_->init_side_done()); assert(gamestate().gamedata_.phase() == game_data::PLAY); mp_ui_alerts::turn_changed(current_team().current_player()); LOG_NG << "events::commands_disabled=" << events::commands_disabled <<"\n"; remove_blindfold(); const std::unique_ptr<countdown_clock> timer(saved_game_.mp_settings().mp_countdown ? new countdown_clock(current_team()) : nullptr); show_turn_dialog(); if(undo_stack().can_undo()) { // If we reload a networked mp game we cannot undo moves made before the save // because other players already received them if(!current_team().auto_shroud_updates()) { synced_context::run_and_store("update_shroud", replay_helper::get_update_shroud()); } undo_stack().clear(); } if (!preferences::disable_auto_moves()) { execute_gotos(); } end_turn_enable(true); while(!should_return_to_play_side()) { try { process_network_data(); check_objectives(); play_slice_catch(); if (player_type_changed_) { // 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.")); color_t color {255,255,255,SDL_ALPHA_OPAQUE}; 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(); } if(timer) { bool time_left = timer->update(); if(!time_left) { end_turn_ = END_TURN_REQUIRED; } } } catch(...) { turn_data_.send_data(); throw; } turn_data_.send_data(); } }
bool play_controller::can_redo() const { return !linger_ && !is_browsing() && !events::commands_disabled && undo_stack().can_redo(); }
void play_controller::redo() { mouse_handler_.deselect_hex(); undo_stack().redo(); }
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(); }
void play_controller::init(CVideo& video, const config& level) { gui2::dialogs::loading_screen::display(video, [this, &video, &level]() { gui2::dialogs::loading_screen::progress("load level"); LOG_NG << "initializing game_state..." << (SDL_GetTicks() - ticks()) << std::endl; gamestate_.reset(new game_state(level, *this, tdata_)); resources::gameboard = &gamestate().board_; resources::gamedata = &gamestate().gamedata_; resources::tod_manager = &gamestate().tod_manager_; resources::units = &gamestate().board_.units_; resources::filter_con = &gamestate(); resources::undo_stack = &undo_stack(); resources::game_events = gamestate().events_manager_.get(); resources::lua_kernel = gamestate().lua_kernel_.get(); gamestate_->init(level, *this); resources::tunnels = gamestate().pathfind_manager_.get(); LOG_NG << "initializing whiteboard..." << (SDL_GetTicks() - ticks()) << std::endl; gui2::dialogs::loading_screen::progress("init whiteboard"); whiteboard_manager_.reset(new wb::manager()); resources::whiteboard = whiteboard_manager_; LOG_NG << "loading units..." << (SDL_GetTicks() - ticks()) << std::endl; gui2::dialogs::loading_screen::progress("load units"); preferences::encounter_all_content(gamestate().board_); LOG_NG << "initializing theme... " << (SDL_GetTicks() - ticks()) << std::endl; gui2::dialogs::loading_screen::progress("init theme"); const config& theme_cfg = controller_base::get_theme(game_config_, level["theme"]); LOG_NG << "building terrain rules... " << (SDL_GetTicks() - ticks()) << std::endl; gui2::dialogs::loading_screen::progress("build terrain"); gui_.reset(new game_display(gamestate().board_, video, whiteboard_manager_, *gamestate().reports_, gamestate().tod_manager_, theme_cfg, level)); if (!gui_->video().faked()) { if (saved_game_.mp_settings().mp_countdown) gui_->get_theme().modify_label("time-icon", _ ("time left for current turn")); else gui_->get_theme().modify_label("time-icon", _ ("current local time")); } gui2::dialogs::loading_screen::progress("init display"); mouse_handler_.set_gui(gui_.get()); menu_handler_.set_gui(gui_.get()); resources::screen = gui_.get(); LOG_NG << "done initializing display... " << (SDL_GetTicks() - ticks()) << std::endl; LOG_NG << "building gamestate to gui and whiteboard... " << (SDL_GetTicks() - ticks()) << std::endl; // This *needs* to be created before the show_intro and show_map_scene // as that functions use the manager state_of_game // Has to be done before registering any events! gamestate().set_game_display(gui_.get()); gui2::dialogs::loading_screen::progress("init lua"); if(gamestate().first_human_team_ != -1) { gui_->set_team(gamestate().first_human_team_); } else if(is_observer()) { // Find first team that is allowed to be observed. // If not set here observer would be without fog until // the first turn of observable side size_t i; for (i=0; i < gamestate().board_.teams().size(); ++i) { if (!gamestate().board_.teams()[i].get_disallow_observers()) { gui_->set_team(i); } } } init_managers(); gui2::dialogs::loading_screen::progress("start game"); //loadscreen_manager->reset(); gamestate().gamedata_.set_phase(game_data::PRELOAD); gamestate().lua_kernel_->load_game(level); plugins_context_.reset(new plugins_context("Game")); plugins_context_->set_callback("save_game", [this](const config& cfg) { save_game_auto(cfg["filename"]); }, true); plugins_context_->set_callback("save_replay", [this](const config& cfg) { save_replay_auto(cfg["filename"]); }, true); plugins_context_->set_callback("quit", throw_end_level(), false); plugins_context_->set_accessor_string("scenario_name", [this](config) { return get_scenario_name(); }); }); //Do this after the loadingscreen, so that ita happens in the main thread. gui_->join(); }
actions::undo_list& get_undo_stack() { return undo_stack(); }