static bool enter_connect_mode(game_display& disp, const config& game_config, game_state& state, const mp_game_settings& params, bool local_players_only = false) { DBG_MP << "entering connect mode" << std::endl; mp::ui::result res; const network::manager net_manager(1,1); network_game_manager m; gamelist.clear(); statistics::fresh_stats(); { mp::connect_engine_ptr connect_engine(new mp::connect_engine(disp, state, params, local_players_only, true)); mp::connect ui(disp, params.name, game_config, gamechat, gamelist, *connect_engine); run_lobby_loop(disp, ui); res = ui.get_result(); // start_game() updates the parameters to reflect game start, // so it must be called before get_level() if (res == mp::ui::PLAY) { ui.start_game(); } } switch (res) { case mp::ui::PLAY: play_game(disp, state, game_config, IO_SERVER, false, !local_players_only); recorder.clear(); break; case mp::ui::CREATE: enter_create_mode(disp, game_config, state, local_players_only); break; case mp::ui::QUIT: default: network::send_data(config("refresh_lobby"), 0); return false; } return true; }
LEVEL_RESULT campaign_controller::play_game() { if(is_replay_) { state_.get_replay().set_pos(0); } else { state_.get_replay().set_to_end(); } state_.expand_scenario(); game_classification::CAMPAIGN_TYPE game_type = state_.classification().campaign_type; while(state_.valid()) { LEVEL_RESULT res = LEVEL_RESULT::VICTORY; end_level_data end_level; try { state_.expand_random_scenario(); //In case this an mp scenario reloaded by sp this was not already done yet. state_.expand_mp_events(); sound::empty_playlist(); state_.expand_carryover(); //expand_mp_options must be called after expand_carryover because expand_carryover will to set previous variables if there are already variables in the [scenario] state_.expand_mp_options(); #if !defined(ALWAYS_USE_MP_CONTROLLER) if (game_type != game_classification::CAMPAIGN_TYPE::MULTIPLAYER || is_replay_) { res = playsingle_scenario(end_level); if(is_replay_) { return res; } } else #endif { res = playmp_scenario(end_level); } } catch(game::load_game_failed& e) { gui2::show_error_message(video_, _("The game could not be loaded: ") + e.message); return LEVEL_RESULT::QUIT; } catch(quit_game_exception&) { LOG_NG << "The game was aborted\n"; return LEVEL_RESULT::QUIT; } catch(game::game_error& e) { gui2::show_error_message(video_, _("Error while playing the game: ") + e.message); return LEVEL_RESULT::QUIT; } catch(incorrect_map_format_error& e) { gui2::show_error_message(video_, std::string(_("The game map could not be loaded: ")) + e.message); return LEVEL_RESULT::QUIT; } catch (mapgen_exception& e) { gui2::show_error_message(video_, std::string(_("Map generator error: ") + e.message)); } catch(config::error& e) { gui2::show_error_message(video_, _("Error while reading the WML: ") + e.message); return LEVEL_RESULT::QUIT; } catch(twml_exception& e) { e.show(video_); return LEVEL_RESULT::QUIT; } if (is_unit_test_) { return res; } if(res == LEVEL_RESULT::QUIT) { return res; } // proceed_to_next_level <=> 'any human side recieved victory' // If 'any human side recieved victory' we do the Save-management options // Otherwise we are done now if(!end_level.proceed_to_next_level) { return res; } if (preferences::delete_saves()) { savegame::clean_saves(state_.classification().label); } if (preferences::save_replays() && end_level.replay_save) { savegame::replay_savegame save(state_, preferences::save_compression_format()); save.save_game_automatic(video_, true); } state_.convert_to_start_save(); //If there is no next scenario we're done now. if(state_.get_scenario_id().empty()) { return res; } else if(res == LEVEL_RESULT::OBSERVER_END && mp_info_ && !mp_info_->is_host) { const int dlg_res = gui2::show_message(video_, _("Game Over"), _("This scenario has ended. Do you want to continue the campaign?"), gui2::tmessage::yes_no_buttons); if(dlg_res == gui2::twindow::CANCEL) { return res; } } if (mp_info_ && !mp_info_->is_host) { // Opens mp::connect dialog to get a new gamestate. mp::ui::result wait_res = mp::goto_mp_wait(video_, state_, game_config_, &mp_info_->wesnothd_connection, res == LEVEL_RESULT::OBSERVER_END); if (wait_res == mp::ui::QUIT) { return LEVEL_RESULT::QUIT; } //The host should send the complete savegame now that also contains the carryvoer sides start. } else { // Retrieve next scenario data. state_.expand_scenario(); if (state_.valid()) { //note that although starting_pos is const it might be changed by gamestate.some_non_const_operation() . const config& starting_pos = state_.get_starting_pos(); const bool is_mp = state_.classification().is_normal_mp_game(); state_.mp_settings().num_turns = starting_pos["turns"].to_int(-1); state_.mp_settings().saved_game = false; state_.mp_settings().use_map_settings = starting_pos["force_lock_settings"].to_bool(!is_mp); ng::connect_engine_ptr connect_engine(new ng::connect_engine(state_, false, mp_info_)); if (!connect_engine->can_start_game() || (game_config::debug && game_type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER)) { // Opens mp::connect dialog to allow users to make an adjustments for scenario. mp::ui::result connect_res = mp::goto_mp_connect(video_, *connect_engine, game_config_, mp_info_ ? &mp_info_->wesnothd_connection : nullptr, state_.mp_settings().name); if (connect_res == mp::ui::QUIT) { return LEVEL_RESULT::QUIT; } } else { // Start the next scenario immediately. connect_engine->start_game(); } } } if(state_.valid()) { // Update the label state_.update_label(); // If this isn't the last scenario, then save the game if(end_level.prescenario_save) { // For multiplayer, we want the save // to contain the starting position. // For campaigns however, this is the // start-of-scenario save and the // starting position needs to be empty, // to force a reload of the scenario config. savegame::scenariostart_savegame save(state_, preferences::save_compression_format()); save.save_game_automatic(video_); } } } if (!state_.get_scenario_id().empty()) { std::string message = _("Unknown scenario: '$scenario|'"); utils::string_map symbols; symbols["scenario"] = state_.get_scenario_id(); message = utils::interpolate_variables_into_string(message, &symbols); gui2::show_error_message(video_, message); return LEVEL_RESULT::QUIT; } if (game_type == game_classification::CAMPAIGN_TYPE::SCENARIO){ if (preferences::delete_saves()) { savegame::clean_saves(state_.classification().label); } } return LEVEL_RESULT::VICTORY; }
void start_local_game_commandline(const config& game_config, saved_game& state, const commandline_options& cmdline_opts) { DBG_MP << "starting local MP game from commandline" << std::endl; // The setup is done equivalently to lobby MP games using as much of existing // code as possible. This means that some things are set up that are not // needed in commandline mode, but they are required by the functions called. preferences::set_message_private(false); DBG_MP << "entering create mode" << std::endl; // Set the default parameters state.clear(); // This creates these parameters with default values defined in mp_game_settings.cpp mp_game_settings& parameters = state.mp_settings(); // Hardcoded default values parameters.mp_era = "era_default"; parameters.name = "multiplayer_The_Freelands"; // Default values for which at getter function exists parameters.num_turns = settings::get_turns(""); parameters.village_gold = settings::get_village_gold(""); parameters.village_support = settings::get_village_support(""); parameters.xp_modifier = settings::get_xp_modifier(""); // Do not use map settings if --ignore-map-settings commandline option is set if(cmdline_opts.multiplayer_ignore_map_settings) { DBG_MP << "ignoring map settings" << std::endl; parameters.use_map_settings = false; } else { parameters.use_map_settings = true; } // None of the other parameters need to be set, as their creation values above are good enough for CL mode. // In particular, we do not want to use the preferences values. state.classification().campaign_type = game_classification::CAMPAIGN_TYPE::MULTIPLAYER; // [era] define. if(cmdline_opts.multiplayer_era) { parameters.mp_era = *cmdline_opts.multiplayer_era; } if(const config& cfg_era = game_config.find_child("era", "id", parameters.mp_era)) { state.classification().era_define = cfg_era["define"].str(); } else { std::cerr << "Could not find era '" << parameters.mp_era << "'\n"; return; } // [multiplayer] define. if(cmdline_opts.multiplayer_scenario) { parameters.name = *cmdline_opts.multiplayer_scenario; } if(const config& cfg_multiplayer = game_config.find_child("multiplayer", "id", parameters.name)) { state.classification().scenario_define = cfg_multiplayer["define"].str(); } else { std::cerr << "Could not find [multiplayer] '" << parameters.name << "'\n"; return; } game_config_manager::get()->load_game_config_for_game(state.classification()); state.set_carryover_sides_start( config {"next_scenario", parameters.name} ); state.expand_random_scenario(); state.expand_mp_events(); state.expand_mp_options(); // Should number of turns be determined from scenario data? if(parameters.use_map_settings && state.get_starting_pos()["turns"]) { DBG_MP << "setting turns from scenario data: " << state.get_starting_pos()["turns"] << std::endl; parameters.num_turns = state.get_starting_pos()["turns"]; } DBG_MP << "entering connect mode" << std::endl; statistics::fresh_stats(); { ng::connect_engine_ptr connect_engine(new ng::connect_engine(state, true, nullptr)); // Update the parameters to reflect game start conditions connect_engine->start_game_commandline(cmdline_opts); } if(resources::recorder && cmdline_opts.multiplayer_label) { std::string label = *cmdline_opts.multiplayer_label; resources::recorder->add_log_data("ai_log","ai_label",label); } unsigned int repeat = (cmdline_opts.multiplayer_repeat) ? *cmdline_opts.multiplayer_repeat : 1; for(unsigned int i = 0; i < repeat; i++){ saved_game state_copy(state); campaign_controller controller(state_copy, game_config, game_config_manager::get()->terrain_types()); controller.play_game(); } }