Merge pull request #201 from gfgtdf/gamestate_refactor
change savefile format & wesnothd protocoll The main intentions of this patch are: 1) To remove redundant information in savefiles 2) To fix mp/sp bugs: "modification [event]s wont be reaplied if one advances from a mp game (also if it was reloaded from sp that was reloaded in sp)" 3) To fix "start-of-scenario mp saves are broken" 4) Clear up playcampaign.cpp s code This patch changes the wesnothd server protocoll causing incompability with oder version regarding networked mutiplayer. We now use the savefile fomat when sending new games to the server. Also between some commits in this pr some mp related things will not work.
This commit is contained in:
commit
fba6cb5f2d
36 changed files with 965 additions and 596 deletions
|
@ -20,6 +20,7 @@
|
|||
#include "team.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include <boost/foreach.hpp>
|
||||
#include <cassert>
|
||||
|
||||
carryover::carryover(const config& side)
|
||||
: add_(side["add"].to_bool())
|
||||
|
@ -33,6 +34,12 @@ carryover::carryover(const config& side)
|
|||
{
|
||||
BOOST_FOREACH(const config& u, side.child_range("unit")){
|
||||
recall_list_.push_back(u);
|
||||
config& u_back = recall_list_.back();
|
||||
u_back.remove_attribute("side");
|
||||
u_back.remove_attribute("goto_x");
|
||||
u_back.remove_attribute("goto_y");
|
||||
u_back.remove_attribute("x");
|
||||
u_back.remove_attribute("y");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,6 +129,10 @@ const std::string carryover::to_string(){
|
|||
return side;
|
||||
}
|
||||
|
||||
void carryover::set_gold(int gold){
|
||||
gold_ = gold;
|
||||
}
|
||||
|
||||
void carryover::to_config(config& cfg){
|
||||
config& side = cfg.add_child("side");
|
||||
side["save_id"] = save_id_;
|
||||
|
@ -135,7 +146,7 @@ void carryover::to_config(config& cfg){
|
|||
side.add_child("unit", u_cfg);
|
||||
}
|
||||
|
||||
carryover_info::carryover_info(const config& cfg)
|
||||
carryover_info::carryover_info(const config& cfg, bool from_snpashot)
|
||||
: carryover_sides_()
|
||||
, end_level_()
|
||||
, variables_(cfg.child_or_empty("variables"))
|
||||
|
@ -144,9 +155,27 @@ carryover_info::carryover_info(const config& cfg)
|
|||
, next_scenario_(cfg["next_scenario"])
|
||||
, next_underlying_unit_id_(cfg["next_underlying_unit_id"].to_int(0))
|
||||
{
|
||||
int turns_left = cfg["turns"].to_int() - cfg["turn_at"].to_int();
|
||||
end_level_.read(cfg.child_or_empty("end_level_data"));
|
||||
BOOST_FOREACH(const config& side, cfg.child_range("side")){
|
||||
BOOST_FOREACH(const config& side, cfg.child_range("side"))
|
||||
{
|
||||
if(side["lost"].to_bool(false) || !side["persistent"].to_bool(true))
|
||||
{
|
||||
//this shouldnt happen outside a snpshot.
|
||||
assert(from_snpashot);
|
||||
continue;
|
||||
}
|
||||
this->carryover_sides_.push_back(carryover(side));
|
||||
if(from_snpashot)
|
||||
{
|
||||
//adjust gold
|
||||
int finishing_bonus_per_turn = cfg["map_villages_num"] * side["village_gold"] + side["income"];
|
||||
int finishing_bonus = std::max(0, finishing_bonus_per_turn * turns_left);
|
||||
if(end_level_.gold_bonus)
|
||||
{
|
||||
carryover_sides_.back().set_gold(div100rounded((finishing_bonus + side["gold"]) * end_level_.carryover_percentage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wml_menu_items_.set_menu_items(cfg);
|
||||
|
@ -296,3 +325,22 @@ carryover* carryover_info::get_side(std::string save_id){
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void carryover_info::merge_old_carryover(const carryover_info& old_carryover)
|
||||
{
|
||||
BOOST_FOREACH(const carryover & old_side, old_carryover.carryover_sides_)
|
||||
{
|
||||
std::vector<carryover>::iterator iside = std::find_if(
|
||||
carryover_sides_.begin(),
|
||||
carryover_sides_.end(),
|
||||
save_id_equals(old_side.get_save_id())
|
||||
);
|
||||
//add the side if don't already have it.
|
||||
if(iside == carryover_sides_.end())
|
||||
{
|
||||
this->carryover_sides_.push_back(old_side);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
void initialize_team(config& side_cfg);
|
||||
const std::string to_string();
|
||||
void to_config(config& cfg);
|
||||
void set_gold(int gold);
|
||||
private:
|
||||
bool add_;
|
||||
std::string color_;
|
||||
|
@ -65,8 +66,9 @@ public:
|
|||
, next_scenario_()
|
||||
, next_underlying_unit_id_()
|
||||
{}
|
||||
// Turns config from a loaded savegame into carryover_info
|
||||
explicit carryover_info(const config& cfg);
|
||||
/// Turns config from a loaded savegame into carryover_info
|
||||
/// @param from_snapshot true if cfg is a [snapshot], false if cfg is [carryover_sides(_start)]
|
||||
explicit carryover_info(const config& cfg, bool from_snapshot = false);
|
||||
|
||||
carryover* get_side(std::string save_id);
|
||||
std::vector<carryover>& get_all_sides();
|
||||
|
@ -94,6 +96,8 @@ public:
|
|||
const std::string& next_scenario() const { return next_scenario_; }
|
||||
|
||||
const config to_config();
|
||||
|
||||
void merge_old_carryover(const carryover_info& old_carryover);
|
||||
private:
|
||||
std::vector<carryover> carryover_sides_;
|
||||
end_level_data end_level_;
|
||||
|
|
|
@ -78,7 +78,9 @@ void game_board::all_survivors_to_recall() {
|
|||
if (teams_[un.side() - 1].persistent()) {
|
||||
un.new_turn();
|
||||
un.new_scenario();
|
||||
#if 0
|
||||
teams_[un.side() - 1].recall_list().push_back(un);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -263,6 +265,9 @@ void game_board::write_config(config & cfg) const {
|
|||
|
||||
//write the map
|
||||
cfg["map_data"] = map_->write();
|
||||
|
||||
//Used by the carryover calculations.
|
||||
cfg["map_villages_num"] = map_->villages().size();
|
||||
}
|
||||
|
||||
temporary_unit_placer::temporary_unit_placer(unit_map& m, const map_location& loc, unit& u)
|
||||
|
|
|
@ -589,10 +589,10 @@ bool game_controller::load_game()
|
|||
recorder.start_replay();
|
||||
recorder.set_skip(false);
|
||||
|
||||
LOG_CONFIG << "has snapshot: " << (state_.snapshot.child("side") ? "yes" : "no") << "\n";
|
||||
LOG_CONFIG << "has is middle game savefile: " << (state_.is_mid_game_save() ? "yes" : "no") << "\n";
|
||||
|
||||
if (!state_.snapshot.child("side")) {
|
||||
// No snapshot; this is a start-of-scenario
|
||||
if (!state_.is_mid_game_save()) {
|
||||
//this is a start-of-scenario
|
||||
if (load.show_replay()) {
|
||||
// There won't be any turns to replay, but the
|
||||
// user gets to watch the intro sequence again ...
|
||||
|
@ -616,7 +616,7 @@ bool game_controller::load_game()
|
|||
}
|
||||
|
||||
if(state_.classification().campaign_type == game_classification::MULTIPLAYER) {
|
||||
BOOST_FOREACH(config &side, state_.snapshot.child_range("side"))
|
||||
BOOST_FOREACH(config &side, state_.get_starting_pos().child_range("side"))
|
||||
{
|
||||
if (side["controller"] == "network")
|
||||
side["controller"] = "human";
|
||||
|
@ -627,7 +627,7 @@ bool game_controller::load_game()
|
|||
}
|
||||
|
||||
if (load.cancel_orders()) {
|
||||
BOOST_FOREACH(config &side, state_.snapshot.child_range("side"))
|
||||
BOOST_FOREACH(config &side, state_.get_starting_pos().child_range("side"))
|
||||
{
|
||||
if (side["controller"] != "human") continue;
|
||||
BOOST_FOREACH(config &unit, side.child_range("unit"))
|
||||
|
@ -790,7 +790,6 @@ bool game_controller::new_campaign()
|
|||
}
|
||||
}
|
||||
|
||||
state_.carryover_sides_start["difficulty"] = difficulties[difficulty];
|
||||
state_.classification().difficulty = difficulties[difficulty];
|
||||
}
|
||||
|
||||
|
|
|
@ -228,6 +228,13 @@ struct end_level_data
|
|||
void write(config& cfg) const;
|
||||
|
||||
void read(const config& cfg);
|
||||
|
||||
config to_config() const
|
||||
{
|
||||
config r;
|
||||
write(r);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* ! GAME_END_EXCEPTIONS_HPP_INCLUDED */
|
||||
|
|
|
@ -700,6 +700,17 @@ void convert_old_saves(config& cfg){
|
|||
carryover_sides_start["next_underlying_unit_id"] = cfg["next_underlying_unit_id"];
|
||||
}
|
||||
}
|
||||
|
||||
if(config& snapshot = cfg.child("snapshot"))
|
||||
{
|
||||
//make [end_level] -> [end_level_data] since its alo called [end_level_data] in the carryover.
|
||||
if(config& end_level = cfg.child("end_level") )
|
||||
{
|
||||
snapshot.add_child("end_level_data", end_level);
|
||||
snapshot.remove_child("end_level",0);
|
||||
}
|
||||
}
|
||||
|
||||
//1.12-1.13 end
|
||||
LOG_RG<<"cfg after conversion "<<cfg<<"\n";
|
||||
}
|
||||
|
|
|
@ -51,8 +51,7 @@ mp_game_settings::mp_game_settings() :
|
|||
share_view(false),
|
||||
share_maps(false),
|
||||
saved_game(false),
|
||||
options(),
|
||||
scenario_data()
|
||||
options()
|
||||
|
||||
{ reset(); }
|
||||
|
||||
|
@ -86,8 +85,7 @@ mp_game_settings::mp_game_settings(const config& cfg) :
|
|||
share_view(false),
|
||||
share_maps(false),
|
||||
saved_game(false),
|
||||
options(),
|
||||
scenario_data()
|
||||
options()
|
||||
{
|
||||
set_from_config(cfg);
|
||||
}
|
||||
|
@ -123,7 +121,6 @@ mp_game_settings::mp_game_settings(const mp_game_settings& settings)
|
|||
, share_maps(settings.share_maps)
|
||||
, saved_game(settings.saved_game)
|
||||
, options(settings.options)
|
||||
, scenario_data(settings.scenario_data)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -184,8 +181,6 @@ void mp_game_settings::reset()
|
|||
mp_countdown=false;
|
||||
use_map_settings = random_start_time = fog_game = shroud_game = allow_observers = shuffle_sides = share_view = share_maps = false;
|
||||
options.clear();
|
||||
|
||||
scenario_data.clear();
|
||||
}
|
||||
|
||||
config mp_game_settings::to_config() const
|
||||
|
|
|
@ -65,12 +65,6 @@ struct mp_game_settings : public savegame::savegame_config
|
|||
bool saved_game;
|
||||
|
||||
config options;
|
||||
|
||||
/**
|
||||
* If the game is to be randomly generated, the map generator
|
||||
* will create the scenario data in this variable
|
||||
*/
|
||||
config scenario_data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -45,64 +45,65 @@ static lg::log_domain log_network("network");
|
|||
|
||||
namespace mp {
|
||||
|
||||
config initial_level_config(game_display& disp, const mp_game_settings& params,
|
||||
saved_game& state)
|
||||
// To remove radundant informaion in the clientside internal programmflow
|
||||
// I want to remove these values from mp_settings so i need to readd them here
|
||||
static void add_multiplayer_classification(config& multiplayer, saved_game& state)
|
||||
{
|
||||
config level;
|
||||
multiplayer["mp_scenario"] = state.get_scenario_id();
|
||||
multiplayer["mp_scenario_name"] = state.get_starting_pos()["name"];
|
||||
multiplayer["difficulty_define"] = state.classification().difficulty;
|
||||
multiplayer["mp_campaign"] = state.classification().campaign;
|
||||
}
|
||||
|
||||
if (params.saved_game) {
|
||||
try {
|
||||
savegame::loadgame load(disp,
|
||||
resources::config_manager->game_config(), state);
|
||||
load.load_multiplayer_game();
|
||||
load.fill_mplevel_config(level);
|
||||
config initial_level_config(saved_game& state)
|
||||
{
|
||||
const mp_game_settings& params = state.mp_settings();
|
||||
//Also impliers state.expand_scenario()
|
||||
//We need to call this before expand_mp_events/options oterwise they might be overwritten
|
||||
state.expand_random_scenario();
|
||||
state.expand_mp_events();
|
||||
state.expand_mp_options();
|
||||
|
||||
resources::config_manager->
|
||||
load_game_config_for_game(state.classification());
|
||||
}
|
||||
catch (load_game_cancelled_exception){
|
||||
return config();
|
||||
} catch(config::error&) {
|
||||
return config();
|
||||
}
|
||||
} else {
|
||||
level.merge_with(params.scenario_data);
|
||||
level["turns"] = params.num_turns;
|
||||
level["difficulty"] = params.difficulty_define;
|
||||
level.add_child("multiplayer", params.to_config());
|
||||
|
||||
// Convert options to events
|
||||
level.add_child_at("event", options::to_event(params.options.find_child(
|
||||
"multiplayer", "id", params.mp_scenario)), 0);
|
||||
if(!level.has_attribute("next_underlying_unit_id"))
|
||||
config& scenario = state.get_starting_pos();
|
||||
if(!state.mp_settings().saved_game)
|
||||
{
|
||||
if(state.carryover_sides_start["random_seed"].str() == "")
|
||||
{
|
||||
level["next_underlying_unit_id"] = 0;
|
||||
state.carryover_sides_start["random_seed"] = rand();
|
||||
state.carryover_sides_start["random_calls"] = 0;
|
||||
}
|
||||
n_unit::id_manager::instance().clear();
|
||||
scenario["turns"] = params.num_turns;
|
||||
|
||||
if (params.random_start_time)
|
||||
{
|
||||
if (!tod_manager::is_start_ToD(level["random_start_time"]))
|
||||
if (!tod_manager::is_start_ToD(scenario["random_start_time"]))
|
||||
{
|
||||
level["random_start_time"] = true;
|
||||
scenario["random_start_time"] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
level["random_start_time"] = false;
|
||||
scenario["random_start_time"] = false;
|
||||
}
|
||||
|
||||
level["experience_modifier"] = params.xp_modifier;
|
||||
level["random_seed"] = state.carryover_sides_start["random_seed"];
|
||||
scenario["experience_modifier"] = params.xp_modifier;
|
||||
}
|
||||
|
||||
if (scenario["objectives"].empty()) {
|
||||
scenario["objectives"] = "<big>" + t_string(N_("Victory:"), "wesnoth") +
|
||||
"</big>\n<span foreground=\"#00ff00\">• " +
|
||||
t_string(N_("Defeat enemy leader(s)"), "wesnoth") + "</span>";
|
||||
}
|
||||
|
||||
config level = state.to_config();
|
||||
add_multiplayer_classification(level.child_or_add("multiplayer"), state);
|
||||
|
||||
std::string era = params.mp_era;
|
||||
if (params.saved_game) {
|
||||
if (const config &c = level.child("snapshot").child("era"))
|
||||
era = c["id"].str();
|
||||
}
|
||||
//[multiplayer] mp_era= shoudl be psersistent over saves.
|
||||
|
||||
//[era], [modification]s are toplevel tags here, they are not part of teh saved_game and only used during mp_connect/mp_wait
|
||||
// Initialize the list of sides available for the current era.
|
||||
// We also need this no not get a segfault in mp_connect for ai configuation
|
||||
const config &era_cfg =
|
||||
resources::config_manager->game_config().find_child("era", "id", era);
|
||||
if (!era_cfg) {
|
||||
|
@ -114,35 +115,30 @@ config initial_level_config(game_display& disp, const mp_game_settings& params,
|
|||
}
|
||||
// FIXME: @todo We should tell user about missing era but still load game
|
||||
WRN_CF << "Missing era in MP load game " << era << std::endl;
|
||||
//Otherwise we get an error when qwhen we try to add ai algirithms in moultiplayer_connect
|
||||
level.add_child("era");
|
||||
}
|
||||
else
|
||||
{
|
||||
config& cfg = level.add_child("era", era_cfg);
|
||||
/*config& cfg = */level.add_child("era", era_cfg);
|
||||
|
||||
const config& custom_side = resources::config_manager->
|
||||
game_config().find_child("multiplayer_side", "id", "Custom");
|
||||
level.child("era").add_child_at("multiplayer_side", custom_side, 0);
|
||||
|
||||
// Convert options to event
|
||||
cfg.add_child_at("event", options::to_event(
|
||||
params.options.find_child("era", "id", era)), 0);
|
||||
}
|
||||
// Add modifications, needed for ai aglorithms which are applied in mp_connect
|
||||
|
||||
// Add modifications
|
||||
const std::vector<std::string>& mods = params.active_mods;
|
||||
for (unsigned i = 0; i < mods.size(); i++) {
|
||||
config& cfg = level.add_child("modification",
|
||||
/*config& cfg = */level.add_child("modification",
|
||||
resources::config_manager->
|
||||
game_config().find_child("modification", "id", mods[i]));
|
||||
|
||||
// Convert options to event
|
||||
cfg.add_child_at("event", options::to_event(
|
||||
params.options.find_child("modification", "id", mods[i])), 0);
|
||||
}
|
||||
|
||||
// This will force connecting clients to be using the same version number as us.
|
||||
level["version"] = game_config::version;
|
||||
|
||||
|
||||
#if 0
|
||||
// we have this alredy in [multiplayer]. If removing this causes a bug than that's most likley bacause some is searchin for this information at the wrng place (not in [multiplayer])
|
||||
// If game was reloaded, params won't contain all required information and so we
|
||||
// need to take it from the actual level config.
|
||||
if (params.saved_game) {
|
||||
|
@ -152,95 +148,60 @@ config initial_level_config(game_display& disp, const mp_game_settings& params,
|
|||
level["observer"] = params.allow_observers;
|
||||
level["shuffle_sides"] = params.shuffle_sides;
|
||||
}
|
||||
|
||||
if (level["objectives"].empty()) {
|
||||
level["objectives"] = "<big>" + t_string(N_("Victory:"), "wesnoth") +
|
||||
"</big>\n<span foreground=\"#00ff00\">• " +
|
||||
t_string(N_("Defeat enemy leader(s)"), "wesnoth") + "</span>";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// This will force connecting clients to be using the same version number as us.
|
||||
level["version"] = game_config::version;
|
||||
return level;
|
||||
}
|
||||
|
||||
void level_to_gamestate(config& level, saved_game& state)
|
||||
void level_to_gamestate(const config& level, saved_game& state)
|
||||
{
|
||||
state = saved_game(level);
|
||||
state.classification().campaign_type = game_classification::MULTIPLAYER;
|
||||
// Any replay data is only temporary and should be removed from
|
||||
// the level data in case we want to save the game later.
|
||||
const config& replay_data = level.child("replay");
|
||||
config replay_data_store;
|
||||
if (replay_data) {
|
||||
replay_data_store = replay_data;
|
||||
if (const config& replay_data = level.child("replay"))
|
||||
{
|
||||
LOG_NW << "setting replay\n";
|
||||
state.replay_data = replay_data;
|
||||
recorder = replay(replay_data_store);
|
||||
recorder = replay(replay_data);
|
||||
if (!recorder.empty()) {
|
||||
recorder.set_skip(false);
|
||||
recorder.set_to_end();
|
||||
}
|
||||
}
|
||||
|
||||
carryover_info sides = carryover_info(state.carryover_sides_start);
|
||||
|
||||
n_unit::id_manager::instance().set_save_id(level["next_underlying_unit_id"]);
|
||||
|
||||
// Set random.
|
||||
const config::attribute_value& seed = level["random_seed"];
|
||||
if (!seed.empty()) {
|
||||
const unsigned calls = level["random_calls"].to_unsigned();
|
||||
sides.rng().seed_random(seed.to_int(42), calls);
|
||||
} else {
|
||||
ERR_NG << "No random seed found, random "
|
||||
"events will probably be out of sync.\n";
|
||||
}
|
||||
|
||||
|
||||
//save id setting was moved to play_controller.
|
||||
|
||||
// Adds the starting pos to the level.
|
||||
if (!level.child("replay_start")) {
|
||||
level.add_child("replay_start", level);
|
||||
level.child("replay_start").remove_child("multiplayer", 0);
|
||||
}
|
||||
|
||||
// This is important, if it does not happen, the starting position is
|
||||
// missing and will be drawn from the snapshot instead
|
||||
// (which is not what we want since we have
|
||||
// all needed information here already).
|
||||
state.replay_start() = level.child("replay_start");
|
||||
//state.replay_start() = level.child("replay_start");
|
||||
|
||||
level["campaign_type"] = lexical_cast<std::string> (game_classification::MULTIPLAYER);
|
||||
state.classification().campaign_type = game_classification::MULTIPLAYER;
|
||||
state.classification().completion = level["completion"].str();
|
||||
state.classification().version = level["version"].str();
|
||||
|
||||
if (const config& vars = level.child("variables")) {
|
||||
sides.set_variables(vars);
|
||||
}
|
||||
sides.get_wml_menu_items().set_menu_items(level);
|
||||
state.mp_settings().set_from_config(level);
|
||||
|
||||
// Check whether it is a save-game by looking for snapshot data.
|
||||
const config& snapshot = level.child("snapshot");
|
||||
const bool saved_game = snapshot && snapshot.child("side");
|
||||
//const config& snapshot = level.child("snapshot");
|
||||
//const bool saved_game = state.mp_settings().saved_game;
|
||||
|
||||
// It might be a MP campaign start-of-scenario save.
|
||||
// In this case, it's not entirely a new game, but not a save, either.
|
||||
// Check whether it is no savegame and the starting_pos
|
||||
// contains [player] information.
|
||||
bool start_of_scenario =
|
||||
!saved_game && state.replay_start().child("player");
|
||||
|
||||
// If we start a fresh game, there won't be any snapshot information.
|
||||
// If however this is a savegame, we got a valid snapshot here.
|
||||
if (saved_game) {
|
||||
state.snapshot = snapshot;
|
||||
if (const config& v = snapshot.child("variables")) {
|
||||
sides.set_variables(v);
|
||||
}
|
||||
sides.get_wml_menu_items().set_menu_items(snapshot);
|
||||
}
|
||||
// Edit: idk what this code did before, but i most liley didn't work because [replay_start] never contains [player]
|
||||
//bool start_of_scenario = !saved_game && state.replay_start().child("player");
|
||||
|
||||
// In any type of reload (normal save or start-of-scenario) the players
|
||||
// could have changed and need to be replaced.
|
||||
if (saved_game || start_of_scenario){
|
||||
// EDIT: We directy use the starting_pos() sides now, so no need to so this anymore.
|
||||
#if 0
|
||||
if (saved_game)
|
||||
{
|
||||
config::child_itors saved_sides = saved_game ?
|
||||
state.snapshot.child_range("side") :
|
||||
state.get_starting_pos().child_range("side") :
|
||||
state.replay_start().child_range("side");
|
||||
config::const_child_itors level_sides = level.child_range("side");
|
||||
|
||||
|
@ -259,14 +220,7 @@ void level_to_gamestate(config& level, saved_game& state)
|
|||
}
|
||||
}
|
||||
}
|
||||
if (sides.get_variables().empty()) {
|
||||
LOG_NG << "No variables were found for the saved_game." << std::endl;
|
||||
} else {
|
||||
LOG_NG << "Variables found and loaded into saved_game:" << std::endl;
|
||||
LOG_NG << sides.get_variables();
|
||||
}
|
||||
|
||||
state.carryover_sides_start = sides.to_config();
|
||||
#endif
|
||||
}
|
||||
|
||||
void check_response(network::connection res, const config& data)
|
||||
|
|
|
@ -23,10 +23,9 @@ class saved_game;
|
|||
|
||||
namespace mp {
|
||||
|
||||
config initial_level_config(game_display& disp, const mp_game_settings& params,
|
||||
saved_game& state);
|
||||
config initial_level_config(saved_game& state);
|
||||
|
||||
void level_to_gamestate(config& level, saved_game& state);
|
||||
void level_to_gamestate(const config& level, saved_game& state);
|
||||
|
||||
void check_response(network::connection res, const config& data);
|
||||
|
||||
|
|
|
@ -474,7 +474,7 @@ static void enter_create_mode(game_display& disp, const config& game_config,
|
|||
saved_game& state, bool local_players_only = false);
|
||||
|
||||
static bool enter_connect_mode(game_display& disp, const config& game_config,
|
||||
saved_game& state, const mp_game_settings& params,
|
||||
saved_game& state,
|
||||
bool local_players_only = false)
|
||||
{
|
||||
DBG_MP << "entering connect mode" << std::endl;
|
||||
|
@ -487,9 +487,8 @@ static bool enter_connect_mode(game_display& disp, const config& game_config,
|
|||
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,
|
||||
mp::connect_engine_ptr connect_engine(new mp::connect_engine(state, local_players_only, true));
|
||||
mp::connect ui(disp, state.mp_settings().name, game_config, gamechat, gamelist,
|
||||
*connect_engine);
|
||||
run_lobby_loop(disp, ui);
|
||||
|
||||
|
@ -522,7 +521,7 @@ static bool enter_connect_mode(game_display& disp, const config& game_config,
|
|||
}
|
||||
|
||||
static bool enter_configure_mode(game_display& disp, const config& game_config,
|
||||
saved_game& state, const mp_game_settings& params,
|
||||
saved_game& state,
|
||||
bool local_players_only = false);
|
||||
|
||||
static void enter_create_mode(game_display& disp, const config& game_config,
|
||||
|
@ -547,23 +546,22 @@ static void enter_create_mode(game_display& disp, const config& game_config,
|
|||
} else {
|
||||
|
||||
mp::ui::result res;
|
||||
mp_game_settings new_params;
|
||||
|
||||
{
|
||||
mp::create ui(disp, game_config, state, gamechat, gamelist);
|
||||
run_lobby_loop(disp, ui);
|
||||
res = ui.get_result();
|
||||
new_params = ui.get_parameters();
|
||||
ui.get_parameters();
|
||||
}
|
||||
|
||||
switch (res) {
|
||||
case mp::ui::CREATE:
|
||||
configure_canceled = !enter_configure_mode(disp, game_config,
|
||||
state, new_params, local_players_only);
|
||||
state, local_players_only);
|
||||
break;
|
||||
case mp::ui::LOAD_GAME:
|
||||
connect_canceled = !enter_connect_mode(disp, game_config,
|
||||
state, new_params, local_players_only);
|
||||
state, local_players_only);
|
||||
break;
|
||||
case mp::ui::QUIT:
|
||||
default:
|
||||
|
@ -576,7 +574,7 @@ static void enter_create_mode(game_display& disp, const config& game_config,
|
|||
}
|
||||
|
||||
static bool enter_configure_mode(game_display& disp, const config& game_config,
|
||||
saved_game& state, const mp_game_settings& params, bool local_players_only)
|
||||
saved_game& state, bool local_players_only)
|
||||
{
|
||||
DBG_MP << "entering configure mode" << std::endl;
|
||||
|
||||
|
@ -586,20 +584,19 @@ static bool enter_configure_mode(game_display& disp, const config& game_config,
|
|||
connect_canceled = false;
|
||||
|
||||
mp::ui::result res;
|
||||
mp_game_settings new_params;
|
||||
|
||||
{
|
||||
mp::configure ui(disp, game_config, gamechat, gamelist, params,
|
||||
mp::configure ui(disp, game_config, gamechat, gamelist, state,
|
||||
local_players_only);
|
||||
run_lobby_loop(disp, ui);
|
||||
res = ui.get_result();
|
||||
new_params = ui.get_parameters();
|
||||
ui.get_parameters();
|
||||
}
|
||||
|
||||
switch (res) {
|
||||
case mp::ui::CREATE:
|
||||
connect_canceled = !enter_connect_mode(disp, game_config,
|
||||
state, new_params, local_players_only);
|
||||
state, local_players_only);
|
||||
break;
|
||||
case mp::ui::QUIT:
|
||||
default:
|
||||
|
@ -765,8 +762,8 @@ void start_local_game_commandline(game_display& disp, const config& game_config,
|
|||
DBG_MP << "entering create mode" << std::endl;
|
||||
|
||||
// Set the default parameters
|
||||
mp_game_settings parameters; // This creates these parameters with default values defined in mp_game_settings.cpp
|
||||
|
||||
state = saved_game(); // 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";
|
||||
|
@ -821,23 +818,23 @@ void start_local_game_commandline(game_display& disp, const config& game_config,
|
|||
// Should the map be randomly generated?
|
||||
if (level["map_generation"].empty()) {
|
||||
DBG_MP << "using scenario map" << std::endl;
|
||||
parameters.scenario_data = level;
|
||||
state.set_scenario(level);
|
||||
} else {
|
||||
DBG_MP << "generating random map" << std::endl;
|
||||
util::scoped_ptr<map_generator> generator(NULL);
|
||||
generator.assign(create_map_generator(level["map_generation"], level.child("generator")));
|
||||
parameters.scenario_data = generator->create_scenario(std::vector<std::string>());
|
||||
state.set_scenario(generator->create_scenario(std::vector<std::string>()));
|
||||
|
||||
// Set the scenario to have placing of sides
|
||||
// based on the terrain they prefer
|
||||
parameters.scenario_data["modify_placing"] = "true";
|
||||
state.get_starting_pos()["modify_placing"] = "true";
|
||||
|
||||
util::unique_ptr<gamemap> map;
|
||||
const int map_positions = level.child("generator")["players"];
|
||||
DBG_MP << "map positions: " << map_positions << std::endl;
|
||||
|
||||
for (int pos = parameters.scenario_data.child_count("side"); pos < map_positions; ++pos) {
|
||||
config& side = parameters.scenario_data.add_child("side");
|
||||
for (int pos = state.get_starting_pos().child_count("side"); pos < map_positions; ++pos) {
|
||||
config& side = state.get_starting_pos().add_child("side");
|
||||
side["side"] = pos + 1;
|
||||
side["team_name"] = pos + 1;
|
||||
side["canrecruit"] = true;
|
||||
|
@ -846,9 +843,9 @@ void start_local_game_commandline(game_display& disp, const config& game_config,
|
|||
}
|
||||
|
||||
// Should number of turns be determined from scenario data?
|
||||
if (parameters.use_map_settings && parameters.scenario_data["turns"]) {
|
||||
DBG_MP << "setting turns from scenario data: " << parameters.scenario_data["turns"] << std::endl;
|
||||
parameters.num_turns = parameters.scenario_data["turns"];
|
||||
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;
|
||||
|
@ -856,8 +853,7 @@ void start_local_game_commandline(game_display& disp, const config& game_config,
|
|||
statistics::fresh_stats();
|
||||
|
||||
{
|
||||
mp::connect_engine_ptr connect_engine(new mp::connect_engine(disp,
|
||||
state, parameters, true, true));
|
||||
mp::connect_engine_ptr connect_engine(new mp::connect_engine(state, true, true));
|
||||
mp::connect ui(disp, parameters.name, game_config, gamechat, gamelist,
|
||||
*connect_engine);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "multiplayer_configure.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "log.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
#include "wml_separators.hpp"
|
||||
#include "formula_string_utils.hpp"
|
||||
|
@ -43,7 +44,7 @@ static lg::log_domain log_mp_configure("mp/configure");
|
|||
|
||||
namespace mp {
|
||||
|
||||
configure::configure(game_display& disp, const config &cfg, chat& c, config& gamelist, const mp_game_settings& params, bool local_players_only) :
|
||||
configure::configure(game_display& disp, const config &cfg, chat& c, config& gamelist, saved_game& game, bool local_players_only) :
|
||||
ui(disp, _("Configure Game"), cfg, c, gamelist),
|
||||
|
||||
local_players_only_(local_players_only),
|
||||
|
@ -90,7 +91,8 @@ configure::configure(game_display& disp, const config &cfg, chat& c, config& gam
|
|||
entry_points_(),
|
||||
show_entry_points_(false),
|
||||
force_use_map_settings_check_(true),
|
||||
parameters_(params),
|
||||
state_(game),
|
||||
parameters_(state_.mp_settings()),
|
||||
options_manager_(cfg, disp, &options_pane_right_, preferences::options())
|
||||
{
|
||||
// Build the list of scenarios to play
|
||||
|
@ -146,7 +148,7 @@ configure::configure(game_display& disp, const config &cfg, chat& c, config& gam
|
|||
xp_modifier_slider_.set_increment(10);
|
||||
xp_modifier_slider_.set_help_string(_("The amount of experience a unit needs to advance"));
|
||||
|
||||
if (parameters_.scenario_data["force_lock_settings"].to_bool()) {
|
||||
if (state_.get_starting_pos()["force_lock_settings"].to_bool()) {
|
||||
use_map_settings_.enable(false);
|
||||
use_map_settings_.set_check(true);
|
||||
} else {
|
||||
|
@ -202,7 +204,7 @@ configure::configure(game_display& disp, const config &cfg, chat& c, config& gam
|
|||
}
|
||||
|
||||
options_manager_.set_era(parameters_.mp_era);
|
||||
options_manager_.set_scenario(parameters_.mp_scenario);
|
||||
options_manager_.set_scenario(state_.get_scenario_id()/*parameters_.mp_scenario*/);
|
||||
options_manager_.set_modifications(parameters_.active_mods);
|
||||
options_manager_.init_widgets();
|
||||
|
||||
|
@ -325,9 +327,7 @@ void configure::process_event()
|
|||
const config& scenario = *entry_points_[entry_points_combo_.selected()];
|
||||
|
||||
parameters_.hash = scenario.hash();
|
||||
parameters_.scenario_data = scenario;
|
||||
parameters_.mp_scenario = scenario["id"].str();
|
||||
parameters_.mp_scenario_name = scenario["name"].str();
|
||||
state_.set_scenario(scenario);
|
||||
|
||||
force_use_map_settings_check_ = true;
|
||||
}
|
||||
|
@ -412,15 +412,15 @@ void configure::process_event()
|
|||
// If the map settings are wanted use them,
|
||||
// if not properly defined fall back to the default settings
|
||||
turns_slider_.set_value(map_settings ?
|
||||
settings::get_turns(parameters_.scenario_data["turns"]) :
|
||||
settings::get_turns(state_.get_starting_pos()["turns"]) :
|
||||
preferences::turns());
|
||||
|
||||
xp_modifier_slider_.set_value(map_settings ?
|
||||
settings::get_xp_modifier(parameters_.scenario_data["experience_modifier"]) :
|
||||
settings::get_xp_modifier(state_.get_starting_pos()["experience_modifier"]) :
|
||||
preferences::xp_modifier());
|
||||
|
||||
random_start_time_.set_check(map_settings ?
|
||||
parameters_.scenario_data["random_start_time"].to_bool(true) :
|
||||
state_.get_starting_pos()["random_start_time"].to_bool(true) :
|
||||
preferences::random_start_time());
|
||||
|
||||
// These are per player, always show values of player 1.
|
||||
|
@ -430,7 +430,7 @@ void configure::process_event()
|
|||
* This might change in the future.
|
||||
* NOTE when 'load game' is selected there are no sides.
|
||||
*/
|
||||
config::const_child_itors sides = parameters_.scenario_data.child_range("side");
|
||||
config::const_child_itors sides = state_.get_starting_pos().child_range("side");
|
||||
if (sides.first != sides.second)
|
||||
{
|
||||
const config &cfg = *sides.first;
|
||||
|
|
|
@ -25,12 +25,15 @@
|
|||
#include "tooltips.hpp"
|
||||
#include "mp_options.hpp"
|
||||
|
||||
class saved_game;
|
||||
namespace mp {
|
||||
|
||||
class configure : public mp::ui
|
||||
{
|
||||
public:
|
||||
configure(game_display& dist, const config& game_config, chat& c, config& gamelist, const mp_game_settings& params, bool local_players_only);
|
||||
///gives the user the option to adjust the passed saved_game
|
||||
///Call get_parameters to finalize;
|
||||
configure(game_display& dist, const config& game_config, chat& c, config& gamelist, saved_game& game, bool local_players_only);
|
||||
~configure();
|
||||
|
||||
const mp_game_settings& get_parameters();
|
||||
|
@ -92,8 +95,8 @@ private:
|
|||
bool show_entry_points_;
|
||||
|
||||
bool force_use_map_settings_check_;
|
||||
mp_game_settings parameters_;
|
||||
|
||||
saved_game& state_;
|
||||
mp_game_settings& parameters_;
|
||||
options::manager options_manager_;
|
||||
};
|
||||
|
||||
|
|
|
@ -395,7 +395,7 @@ connect::connect(game_display& disp, const std::string& game_name,
|
|||
if (get_result() == QUIT || get_result() == CREATE) {
|
||||
return;
|
||||
}
|
||||
if (engine_.level()["id"].empty()) {
|
||||
if (engine_.scenario()["id"].empty()) {
|
||||
throw config::error(_("The scenario is invalid because it has no id."));
|
||||
}
|
||||
|
||||
|
@ -426,7 +426,7 @@ connect::connect(game_display& disp, const std::string& game_name,
|
|||
side_pos_y_offset += 60;
|
||||
}
|
||||
|
||||
append_to_title(" — " + engine_.level()["name"].t_str());
|
||||
append_to_title(" — " + engine_.scenario()["name"].t_str());
|
||||
gold_title_label_.hide(params().saved_game);
|
||||
income_title_label_.hide(params().saved_game);
|
||||
|
||||
|
|
|
@ -69,12 +69,11 @@ const std::string attributes_to_trim[] = {
|
|||
|
||||
namespace mp {
|
||||
|
||||
connect_engine::connect_engine(game_display& disp, saved_game& state,
|
||||
const mp_game_settings& params, const bool local_players_only,
|
||||
const bool first_scenario) :
|
||||
connect_engine::connect_engine(saved_game& state,
|
||||
const bool local_players_only, const bool first_scenario) :
|
||||
level_(),
|
||||
state_(state),
|
||||
params_(params),
|
||||
params_(state.mp_settings()),
|
||||
default_controller_(local_players_only ? CNTR_LOCAL: CNTR_NETWORK),
|
||||
local_players_only_(local_players_only),
|
||||
first_scenario_(first_scenario),
|
||||
|
@ -87,12 +86,12 @@ connect_engine::connect_engine(game_display& disp, saved_game& state,
|
|||
connected_users_()
|
||||
{
|
||||
// Initial level config from the mp_game_settings.
|
||||
level_ = initial_level_config(disp, params_, state_);
|
||||
level_ = initial_level_config(state_);
|
||||
if (level_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
force_lock_settings_ = level_["force_lock_settings"].to_bool();
|
||||
force_lock_settings_ = (!state.mp_settings().saved_game) && scenario()["force_lock_settings"].to_bool();
|
||||
|
||||
// Original level sides.
|
||||
config::child_itors sides = current_config()->child_range("side");
|
||||
|
@ -208,25 +207,10 @@ connect_engine::~connect_engine()
|
|||
}
|
||||
|
||||
config* connect_engine::current_config() {
|
||||
config* cfg_level = NULL;
|
||||
|
||||
// It might make sense to invent a mechanism of some sort to check
|
||||
// whether a config node contains information
|
||||
// that you can load from(side information, specifically).
|
||||
config &snapshot = level_.child("snapshot");
|
||||
if (snapshot && snapshot.child("side")) {
|
||||
// Savegame.
|
||||
cfg_level = &snapshot;
|
||||
} else if (!level_.child("side")) {
|
||||
// Start-of-scenario save,
|
||||
// the info has to be taken from the starting_pos.
|
||||
cfg_level = &state_.replay_start();
|
||||
} else {
|
||||
// Fresh game, no snapshot available.
|
||||
cfg_level = &level_;
|
||||
}
|
||||
|
||||
return cfg_level;
|
||||
if(config& s = scenario())
|
||||
return &s;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void connect_engine::import_user(const std::string& name, const bool observer,
|
||||
|
@ -312,25 +296,18 @@ void connect_engine::update_level()
|
|||
{
|
||||
DBG_MP << "updating level" << std::endl;
|
||||
|
||||
level_.clear_children("side");
|
||||
scenario().clear_children("side");
|
||||
|
||||
BOOST_FOREACH(side_engine_ptr side, side_engines_) {
|
||||
level_.add_child("side", side->new_config());
|
||||
scenario().add_child("side", side->new_config());
|
||||
}
|
||||
}
|
||||
|
||||
void connect_engine::update_and_send_diff(bool update_time_of_day)
|
||||
void connect_engine::update_and_send_diff(bool /*update_time_of_day*/)
|
||||
{
|
||||
config old_level = level_;
|
||||
update_level();
|
||||
|
||||
if (update_time_of_day) {
|
||||
// Set random start ToD.
|
||||
// This doesn't do anything since the "const" parameter is now really a const.
|
||||
// We currently resolve the random tod on all clients seperately with the synced rng.
|
||||
tod_manager tod_mng(level_);
|
||||
}
|
||||
|
||||
config diff = level_.get_diff(old_level);
|
||||
if (!diff.empty()) {
|
||||
config scenario_diff;
|
||||
|
@ -543,7 +520,7 @@ void connect_engine::start_game_commandline(
|
|||
if (cmdline_opts.multiplayer_turns) {
|
||||
DBG_MP << "\tsetting turns: " << cmdline_opts.multiplayer_turns <<
|
||||
std::endl;
|
||||
level_["turns"] = *cmdline_opts.multiplayer_turns;
|
||||
scenario()["turns"] = *cmdline_opts.multiplayer_turns;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(config &side, level_.child_range("side"))
|
||||
|
|
|
@ -43,8 +43,8 @@ typedef std::pair<mp::controller, std::string> controller_option;
|
|||
class connect_engine
|
||||
{
|
||||
public:
|
||||
connect_engine(game_display& disp, saved_game& state,
|
||||
const mp_game_settings& params, const bool local_players_only,
|
||||
connect_engine(saved_game& state,
|
||||
const bool local_players_only,
|
||||
const bool first_scenario);
|
||||
~connect_engine();
|
||||
|
||||
|
@ -84,6 +84,15 @@ public:
|
|||
/* Setters & Getters */
|
||||
|
||||
const config& level() const { return level_; }
|
||||
config& scenario()
|
||||
{
|
||||
if(config& scenario = level_.child("scenario"))
|
||||
return scenario;
|
||||
else if(config& snapshot = level_.child("snapshot"))
|
||||
return snapshot;
|
||||
else
|
||||
throw "No scenariodata found";
|
||||
}
|
||||
const std::set<std::string>& connected_users() const
|
||||
{ return connected_users_; }
|
||||
const std::vector<std::string>& user_team_names()
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include "minimap.hpp"
|
||||
#include "multiplayer_create.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "log.hpp"
|
||||
#include "wml_exception.hpp"
|
||||
#include "wml_separators.hpp"
|
||||
|
@ -253,11 +255,25 @@ void create::process_event()
|
|||
}
|
||||
|
||||
if (load_game_.pressed()) {
|
||||
engine_.prepare_for_saved_game();
|
||||
try
|
||||
{
|
||||
savegame::loadgame load(disp_,
|
||||
resources::config_manager->game_config(), engine_.get_state());
|
||||
load.load_multiplayer_game();
|
||||
|
||||
set_result(LOAD_GAME);
|
||||
engine_.prepare_for_saved_game();
|
||||
|
||||
set_result(LOAD_GAME);
|
||||
|
||||
return;
|
||||
}
|
||||
catch (load_game_cancelled_exception)
|
||||
{
|
||||
}
|
||||
catch(config::error&)
|
||||
{
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool update_mod_button_label = mod_selection_ != mods_menu_.selection();
|
||||
|
|
|
@ -344,7 +344,6 @@ create_engine::create_engine(game_display& disp, saved_game& state) :
|
|||
eras_(),
|
||||
mods_(),
|
||||
state_(state),
|
||||
parameters_(),
|
||||
dependency_manager_(resources::config_manager->game_config(), disp.video()),
|
||||
generator_(NULL)
|
||||
{
|
||||
|
@ -369,17 +368,17 @@ create_engine::create_engine(game_display& disp, saved_game& state) :
|
|||
init_extras(ERA);
|
||||
init_extras(MOD);
|
||||
|
||||
parameters_.saved_game = false;
|
||||
state_.mp_settings().saved_game = false;
|
||||
|
||||
BOOST_FOREACH (const std::string& str, preferences::modifications()) {
|
||||
if (resources::config_manager->
|
||||
game_config().find_child("modification", "id", str))
|
||||
parameters_.active_mods.push_back(str);
|
||||
state_.mp_settings().active_mods.push_back(str);
|
||||
}
|
||||
|
||||
if (current_level_type_ != level::CAMPAIGN &&
|
||||
current_level_type_ != level::SP_CAMPAIGN) {
|
||||
dependency_manager_.try_modifications(parameters_.active_mods, true);
|
||||
dependency_manager_.try_modifications(state_.mp_settings().active_mods, true);
|
||||
}
|
||||
|
||||
reset_level_filters();
|
||||
|
@ -409,10 +408,8 @@ void create_engine::prepare_for_new_level()
|
|||
{
|
||||
DBG_MP << "preparing mp_game_settings for new level\n";
|
||||
|
||||
parameters_.scenario_data = current_level().data();
|
||||
parameters_.hash = parameters_.scenario_data.hash();
|
||||
parameters_.mp_scenario = parameters_.scenario_data["id"].str();
|
||||
parameters_.mp_scenario_name = parameters_.scenario_data["name"].str();
|
||||
state_.set_scenario(current_level().data());
|
||||
state_.mp_settings().hash = current_level().data().hash();
|
||||
}
|
||||
|
||||
void create_engine::prepare_for_campaign(const std::string& difficulty)
|
||||
|
@ -420,9 +417,7 @@ void create_engine::prepare_for_campaign(const std::string& difficulty)
|
|||
DBG_MP << "preparing data for campaign by reloading game config\n";
|
||||
|
||||
if (difficulty != "") {
|
||||
state_.carryover_sides_start["difficulty"] = difficulty;
|
||||
state_.classification().difficulty = difficulty;
|
||||
parameters_.difficulty_define = difficulty;
|
||||
}
|
||||
|
||||
state_.classification().campaign = current_level().data()["id"].str();
|
||||
|
@ -444,20 +439,20 @@ void create_engine::prepare_for_campaign(const std::string& difficulty)
|
|||
resources::config_manager->game_config().find_child(
|
||||
lexical_cast<std::string> (game_classification::MULTIPLAYER),
|
||||
"id", current_level().data()["first_scenario"]));
|
||||
|
||||
parameters_.mp_campaign = current_level().id();
|
||||
}
|
||||
|
||||
void create_engine::prepare_for_saved_game()
|
||||
{
|
||||
DBG_MP << "preparing mp_game_settings for saved game\n";
|
||||
|
||||
parameters_.saved_game = true;
|
||||
parameters_.scenario_data.clear();
|
||||
resources::config_manager->load_game_config_for_game(state_.classification());
|
||||
//The save migh be a start-of-scenario save so make sure we have the scenario data loaded.
|
||||
state_.expand_scenario();
|
||||
state_.mp_settings().saved_game = true;
|
||||
|
||||
utils::string_map i18n_symbols;
|
||||
i18n_symbols["login"] = preferences::login();
|
||||
parameters_.name = vgettext("$login|’s game", i18n_symbols);
|
||||
state_.mp_settings().name = vgettext("$login|’s game", i18n_symbols);
|
||||
}
|
||||
|
||||
void create_engine::apply_level_filter(const std::string &name)
|
||||
|
@ -643,7 +638,7 @@ bool create_engine::toggle_current_mod()
|
|||
bool is_active = dependency_manager_.is_modification_active(current_mod_index_);
|
||||
dependency_manager_.try_modification_by_index(current_mod_index_, !is_active);
|
||||
|
||||
parameters_.active_mods = dependency_manager_.get_modifications();
|
||||
state_.mp_settings().active_mods = dependency_manager_.get_modifications();
|
||||
|
||||
return !is_active;
|
||||
}
|
||||
|
@ -763,12 +758,12 @@ const depcheck::manager& create_engine::dependency_manager() const
|
|||
|
||||
void create_engine::init_active_mods()
|
||||
{
|
||||
parameters_.active_mods = dependency_manager_.get_modifications();
|
||||
state_.mp_settings().active_mods = dependency_manager_.get_modifications();
|
||||
}
|
||||
|
||||
std::vector<std::string>& create_engine::active_mods()
|
||||
{
|
||||
return parameters_.active_mods;
|
||||
return state_.mp_settings().active_mods;
|
||||
}
|
||||
|
||||
const mp_game_settings& create_engine::get_parameters()
|
||||
|
@ -776,9 +771,9 @@ const mp_game_settings& create_engine::get_parameters()
|
|||
DBG_MP << "getting parameter values" << std::endl;
|
||||
|
||||
int era_index = current_level().allow_era_choice() ? current_era_index_ : 0;
|
||||
parameters_.mp_era = eras_[era_index]->id;
|
||||
state_.mp_settings().mp_era = eras_[era_index]->id;
|
||||
|
||||
return parameters_;
|
||||
return state_.mp_settings();
|
||||
}
|
||||
|
||||
void create_engine::init_all_levels()
|
||||
|
@ -1062,4 +1057,9 @@ std::vector<create_engine::extras_metadata_ptr>&
|
|||
return (extra_type == ERA) ? eras_ : mods_;
|
||||
}
|
||||
|
||||
saved_game& create_engine::get_state()
|
||||
{
|
||||
return state_;
|
||||
}
|
||||
|
||||
} // end namespace mp
|
||||
|
|
|
@ -223,6 +223,7 @@ public:
|
|||
|
||||
const mp_game_settings& get_parameters();
|
||||
|
||||
saved_game& get_state();
|
||||
private:
|
||||
create_engine(const create_engine&);
|
||||
void operator=(const create_engine&);
|
||||
|
@ -268,7 +269,6 @@ private:
|
|||
std::vector<extras_metadata_ptr> mods_;
|
||||
|
||||
saved_game& state_;
|
||||
mp_game_settings parameters_;
|
||||
|
||||
depcheck::manager dependency_manager_;
|
||||
|
||||
|
|
|
@ -224,7 +224,7 @@ void wait::join_game(bool observe)
|
|||
if (!download_res) {
|
||||
set_result(QUIT);
|
||||
return;
|
||||
} else if (!level_["allow_new_game"].to_bool(true)) {
|
||||
} else if (!get_scenario()["allow_new_game"].to_bool(true) && !level_.child_or_empty("multiplayer")["savegame"].to_bool(false)) {
|
||||
set_result(PLAY);
|
||||
return;
|
||||
}
|
||||
|
@ -235,10 +235,10 @@ void wait::join_game(bool observe)
|
|||
|
||||
const config* campaign = &resources::config_manager->
|
||||
game_config().find_child("campaign", "id",
|
||||
level_.child(lexical_cast<std::string>(game_classification::MULTIPLAYER))["mp_campaign"]);
|
||||
level_.child("multiplayer")["mp_campaign"]);
|
||||
if (*campaign) {
|
||||
state_.classification().difficulty =
|
||||
level_.child(lexical_cast<std::string>(game_classification::MULTIPLAYER))["difficulty_define"].str();
|
||||
level_.child("multiplayer")["difficulty_define"].str();
|
||||
state_.classification().campaign_define =
|
||||
(*campaign)["define"].str();
|
||||
state_.classification().campaign_xtra_defines =
|
||||
|
@ -251,7 +251,7 @@ void wait::join_game(bool observe)
|
|||
}
|
||||
|
||||
// Add the map name to the title.
|
||||
append_to_title(": " + level_["name"].t_str());
|
||||
append_to_title(": " + get_scenario()["name"].t_str());
|
||||
|
||||
if (!observe) {
|
||||
//search for an appropriate vacant slot. If a description is set
|
||||
|
@ -260,7 +260,7 @@ void wait::join_game(bool observe)
|
|||
//available side.
|
||||
const config *side_choice = NULL;
|
||||
int side_num = -1, nb_sides = 0;
|
||||
BOOST_FOREACH(const config &sd, level_.child_range("side"))
|
||||
BOOST_FOREACH(const config &sd, get_scenario().child_range("side"))
|
||||
{
|
||||
if (sd["controller"] == "reserved" && sd["current_player"] == preferences::login())
|
||||
{
|
||||
|
@ -315,7 +315,7 @@ void wait::join_game(bool observe)
|
|||
}
|
||||
|
||||
const bool lock_settings =
|
||||
level_["force_lock_settings"].to_bool();
|
||||
get_scenario()["force_lock_settings"].to_bool();
|
||||
const bool saved_game =
|
||||
level_.child("multiplayer")["savegame"].to_bool();
|
||||
|
||||
|
@ -462,17 +462,17 @@ void wait::process_network_data(const config& data, const network::connection so
|
|||
LOG_RG << data.debug() << std::endl;
|
||||
//const int side = lexical_cast<int>(change["side"]);
|
||||
|
||||
if (config & sidetochange = level_.find_child("side", "side", change["side"])) {
|
||||
if (config & sidetochange = get_scenario().find_child("side", "side", change["side"])) {
|
||||
LOG_RG << "found side : " << sidetochange.debug() << std::endl;
|
||||
sidetochange.merge_with(change);
|
||||
LOG_RG << "changed to : " << sidetochange.debug() << std::endl;
|
||||
} else {
|
||||
LOG_RG << "change_controller didn't find any side!" << std::endl;
|
||||
}
|
||||
} else if(data.child("side") || data.child("next_scenario")) {
|
||||
} else if(data.has_child("scenario") || data.has_child("snapshot") || data.child("next_scenario")) {
|
||||
level_ = first_scenario_ ? data : data.child("next_scenario");
|
||||
LOG_NW << "got some sides. Current number of sides = "
|
||||
<< level_.child_count("side") << ','
|
||||
<< get_scenario().child_count("side") << ','
|
||||
<< data.child_count("side") << '\n';
|
||||
generate_menu();
|
||||
}
|
||||
|
@ -486,7 +486,7 @@ void wait::generate_menu()
|
|||
std::vector<std::string> details;
|
||||
std::vector<std::string> playerlist;
|
||||
|
||||
BOOST_FOREACH(const config &sd, level_.child_range("side"))
|
||||
BOOST_FOREACH(const config &sd, get_scenario().child_range("side"))
|
||||
{
|
||||
if (!sd["allow_player"].to_bool(true)) {
|
||||
continue;
|
||||
|
@ -600,7 +600,7 @@ void wait::generate_menu()
|
|||
bool wait::has_level_data() const
|
||||
{
|
||||
if (first_scenario_) {
|
||||
return level_.has_attribute("version") && level_.has_child("side");
|
||||
return level_.has_attribute("version") && get_scenario().has_child("side");
|
||||
} else {
|
||||
return level_.has_child("next_scenario");
|
||||
}
|
||||
|
@ -634,5 +634,26 @@ bool wait::download_level_data()
|
|||
return true;
|
||||
}
|
||||
|
||||
config& wait::get_scenario()
|
||||
{
|
||||
|
||||
if(config& scenario = level_.child("scenario"))
|
||||
return scenario;
|
||||
else if(config& snapshot = level_.child("snapshot"))
|
||||
return snapshot;
|
||||
else
|
||||
return level_;
|
||||
}
|
||||
|
||||
const config& wait::get_scenario() const
|
||||
{
|
||||
if(const config& scenario = level_.child("scenario"))
|
||||
return scenario;
|
||||
else if(const config& snapshot = level_.child("snapshot"))
|
||||
return snapshot;
|
||||
else
|
||||
return level_;
|
||||
}
|
||||
|
||||
} // namespace mp
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@ private:
|
|||
void generate_menu();
|
||||
bool has_level_data() const;
|
||||
bool download_level_data();
|
||||
config& get_scenario();
|
||||
const config& get_scenario() const;
|
||||
|
||||
gui::button cancel_button_;
|
||||
gui::label start_label_;
|
||||
|
|
|
@ -752,7 +752,7 @@ config play_controller::to_config() const
|
|||
if(linger_) {
|
||||
config endlevel;
|
||||
end_level_data_.write(endlevel);
|
||||
cfg.add_child("endlevel", endlevel);
|
||||
cfg.add_child("end_level_data", endlevel);
|
||||
}
|
||||
|
||||
// Write terrain_graphics data in snapshot, too
|
||||
|
|
|
@ -52,27 +52,11 @@
|
|||
|
||||
static lg::log_domain log_engine("engine");
|
||||
#define LOG_NG LOG_STREAM(info, log_engine)
|
||||
#define ERR_NG LOG_STREAM(err, log_engine)
|
||||
|
||||
static lg::log_domain log_enginerefac("enginerefac");
|
||||
#define LOG_RG LOG_STREAM(info, log_enginerefac)
|
||||
|
||||
static void team_init(config& level, saved_game& gamestate){
|
||||
//if we are at the start of a new scenario, initialize carryover_sides
|
||||
if(gamestate.snapshot.child_or_empty("variables")["turn_number"].to_int(-1)<1){
|
||||
gamestate.carryover_sides = gamestate.carryover_sides_start;
|
||||
|
||||
|
||||
carryover_info sides(gamestate.carryover_sides);
|
||||
|
||||
sides.transfer_to(level);
|
||||
BOOST_FOREACH(config& side_cfg, level.child_range("side")){
|
||||
sides.transfer_all_to(side_cfg);
|
||||
}
|
||||
|
||||
gamestate.carryover_sides = sides.to_config();
|
||||
}
|
||||
}
|
||||
|
||||
static void store_carryover(saved_game& gamestate, playsingle_controller& playcontroller, display& disp, const end_level_data& end_level, const LEVEL_RESULT res){
|
||||
bool has_next_scenario = !resources::gamedata->next_scenario().empty() &&
|
||||
resources::gamedata->next_scenario() != "null";
|
||||
|
@ -82,10 +66,6 @@ static void store_carryover(saved_game& gamestate, playsingle_controller& playco
|
|||
return;
|
||||
}
|
||||
|
||||
carryover_info sides(gamestate.carryover_sides);
|
||||
|
||||
sides.transfer_from(*resources::gamedata);
|
||||
|
||||
std::ostringstream report;
|
||||
std::string title;
|
||||
|
||||
|
@ -124,19 +104,12 @@ static void store_carryover(saved_game& gamestate, playsingle_controller& playco
|
|||
|
||||
BOOST_FOREACH(const team &t, teams)
|
||||
{
|
||||
if (!t.persistent()){
|
||||
continue;
|
||||
} else if (t.lost()) {
|
||||
sides.remove_side(t.save_id());
|
||||
if (!t.persistent() || t.lost() || !t.is_human())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int carryover_gold = div100rounded((t.gold() + finishing_bonus) * end_level.carryover_percentage);
|
||||
sides.transfer_from(t, carryover_gold);
|
||||
|
||||
if (!t.is_human()){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (persistent_teams > 1) {
|
||||
report << "\n<b>" << t.current_player() << "</b>\n";
|
||||
}
|
||||
|
@ -148,41 +121,6 @@ static void store_carryover(saved_game& gamestate, playsingle_controller& playco
|
|||
if (end_level.transient.carryover_report) {
|
||||
gui2::show_transient_message(disp.video(), title, report.str(), "", true);
|
||||
}
|
||||
|
||||
gamestate.carryover_sides_start = sides.to_config();
|
||||
}
|
||||
|
||||
static void generate_scenario(config const*& scenario)
|
||||
{
|
||||
LOG_G << "randomly generating scenario...\n";
|
||||
const cursor::setter cursor_setter(cursor::WAIT);
|
||||
|
||||
static config new_scenario;
|
||||
new_scenario = random_generate_scenario((*scenario)["scenario_generation"],
|
||||
scenario->child("generator"));
|
||||
|
||||
//TODO comment or remove
|
||||
//level_ = scenario;
|
||||
//merge carryover information into the newly generated scenario
|
||||
|
||||
scenario = &new_scenario;
|
||||
}
|
||||
|
||||
static void generate_map(config const*& scenario)
|
||||
{
|
||||
LOG_G << "randomly generating map...\n";
|
||||
const cursor::setter cursor_setter(cursor::WAIT);
|
||||
|
||||
const std::string map_data = random_generate_map(
|
||||
(*scenario)["map_generation"], scenario->child("generator"));
|
||||
|
||||
// Since we've had to generate the map,
|
||||
// make sure that when we save the game,
|
||||
// it will not ask for the map to be generated again on reload
|
||||
static config new_scenario;
|
||||
new_scenario = *scenario;
|
||||
new_scenario["map_data"] = map_data;
|
||||
scenario = &new_scenario;
|
||||
}
|
||||
|
||||
LEVEL_RESULT play_replay(display& disp, saved_game& gamestate, const config& game_config,
|
||||
|
@ -191,12 +129,8 @@ LEVEL_RESULT play_replay(display& disp, saved_game& gamestate, const config& gam
|
|||
const std::string campaign_type_str = lexical_cast<std::string> (gamestate.classification().campaign_type);
|
||||
|
||||
// 'starting_pos' will contain the position we start the game from.
|
||||
const config& starting_pos = gamestate.replay_start();
|
||||
|
||||
//for replays, use the variables specified in starting_pos
|
||||
if (const config &vars = starting_pos.child("variables")) {
|
||||
gamestate.carryover_sides_start.child_or_add("variables") = vars;
|
||||
}
|
||||
// this call also might expand [scenario] in case thatt there is no replay_start
|
||||
const config& starting_pos = gamestate.get_replay_starting_pos();
|
||||
|
||||
try {
|
||||
// Preserve old label eg. replay
|
||||
|
@ -207,7 +141,6 @@ LEVEL_RESULT play_replay(display& disp, saved_game& gamestate, const config& gam
|
|||
|
||||
LEVEL_RESULT res = play_replay_level(game_config, video, gamestate, is_unit_test);
|
||||
|
||||
gamestate.snapshot = config();
|
||||
recorder.clear();
|
||||
gamestate.replay_data.clear();
|
||||
|
||||
|
@ -246,17 +179,16 @@ LEVEL_RESULT play_replay(display& disp, saved_game& gamestate, const config& gam
|
|||
}
|
||||
|
||||
static LEVEL_RESULT playsingle_scenario(const config& game_config,
|
||||
const config* level, display& disp, saved_game& state_of_game,
|
||||
display& disp, saved_game& state_of_game,
|
||||
const config::const_child_itors &story,
|
||||
bool skip_replay, end_level_data &end_level)
|
||||
{
|
||||
const int ticks = SDL_GetTicks();
|
||||
|
||||
config init_level = *level;
|
||||
team_init(init_level, state_of_game);
|
||||
|
||||
|
||||
state_of_game.expand_carryover();
|
||||
|
||||
LOG_NG << "creating objects... " << (SDL_GetTicks() - ticks) << "\n";
|
||||
playsingle_controller playcontroller(init_level, state_of_game, ticks, game_config, disp.video(), skip_replay);
|
||||
playsingle_controller playcontroller(state_of_game.get_starting_pos(), state_of_game, ticks, game_config, disp.video(), skip_replay);
|
||||
LOG_NG << "created objects... " << (SDL_GetTicks() - playcontroller.get_ticks()) << "\n";
|
||||
|
||||
LEVEL_RESULT res = playcontroller.play_scenario(story, skip_replay);
|
||||
|
@ -284,22 +216,21 @@ static LEVEL_RESULT playsingle_scenario(const config& game_config,
|
|||
}
|
||||
}
|
||||
}
|
||||
state_of_game.set_snapshot(playcontroller.to_config());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static LEVEL_RESULT playmp_scenario(const config& game_config,
|
||||
const config* level, display& disp, saved_game& state_of_game,
|
||||
display& disp, saved_game& state_of_game,
|
||||
const config::const_child_itors &story, bool skip_replay,
|
||||
bool blindfold_replay, io_type_t& io_type, end_level_data &end_level)
|
||||
{
|
||||
const int ticks = SDL_GetTicks();
|
||||
state_of_game.expand_carryover();
|
||||
|
||||
config init_level = *level;
|
||||
team_init(init_level, state_of_game);
|
||||
|
||||
playmp_controller playcontroller(init_level, state_of_game, ticks,
|
||||
playmp_controller playcontroller(state_of_game.get_starting_pos(), state_of_game, ticks,
|
||||
game_config, disp.video(), skip_replay, blindfold_replay, io_type == IO_SERVER);
|
||||
LEVEL_RESULT res = playcontroller.play_scenario(story, skip_replay);
|
||||
|
||||
|
@ -334,8 +265,9 @@ static LEVEL_RESULT playmp_scenario(const config& game_config,
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
state_of_game.set_snapshot(playcontroller.to_config());
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -345,74 +277,12 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
|
|||
{
|
||||
const std::string campaign_type_str = lexical_cast_default<std::string> (gamestate.classification().campaign_type);
|
||||
|
||||
config const* scenario = NULL;
|
||||
gamestate.expand_scenario();
|
||||
|
||||
// 'starting_pos' will contain the position we start the game from.
|
||||
config starting_pos;
|
||||
while(gamestate.valid()) {
|
||||
config& starting_pos = gamestate.get_starting_pos();
|
||||
config::const_child_itors story = starting_pos.child_range("story");
|
||||
|
||||
carryover_info sides = carryover_info(gamestate.carryover_sides_start);
|
||||
|
||||
// Do we have any snapshot data?
|
||||
// yes => this must be a savegame
|
||||
// no => we are starting a fresh scenario
|
||||
if (!gamestate.snapshot.child("side"))
|
||||
{
|
||||
gamestate.classification().completion = "running";
|
||||
// Campaign or Multiplayer?
|
||||
// If the gamestate already contains a starting_pos,
|
||||
// then we are starting a fresh multiplayer game.
|
||||
// Otherwise this is the start of a campaign scenario.
|
||||
if(gamestate.replay_start()["id"].empty() == false) {
|
||||
starting_pos = gamestate.replay_start();
|
||||
scenario = &starting_pos;
|
||||
|
||||
if(gamestate.replay_start()["random_seed"] != gamestate.carryover_sides_start["random_seed"]){
|
||||
sides = carryover_info(gamestate.replay_start());
|
||||
}
|
||||
|
||||
} else {
|
||||
//reload of the scenario, as starting_pos contains carryover information only
|
||||
LOG_G << "loading scenario: '" << sides.next_scenario() << "'\n";
|
||||
scenario = &game_config.find_child(campaign_type_str, "id", sides.next_scenario());
|
||||
|
||||
if(!*scenario){
|
||||
scenario = NULL;
|
||||
}
|
||||
LOG_G << "scenario found: " << (scenario != NULL ? "yes" : "no") << "\n";
|
||||
|
||||
}
|
||||
} else {
|
||||
// This game was started from a savegame
|
||||
LOG_G << "loading snapshot...\n";
|
||||
starting_pos = gamestate.replay_start();
|
||||
scenario = &gamestate.snapshot;
|
||||
// When starting wesnoth --multiplayer there might be
|
||||
// no variables which leads to a segfault
|
||||
if (const config &vars = gamestate.snapshot.child("variables")) {
|
||||
sides.set_variables(vars);
|
||||
}
|
||||
sides.get_wml_menu_items().set_menu_items(gamestate.snapshot);
|
||||
// Replace game label with that from snapshot
|
||||
if (!gamestate.snapshot["label"].empty()){
|
||||
gamestate.classification().label = gamestate.snapshot["label"].str();
|
||||
}
|
||||
}
|
||||
|
||||
gamestate.carryover_sides_start = sides.to_config();
|
||||
|
||||
while(scenario != NULL) {
|
||||
// If we are a multiplayer client, tweak the controllers
|
||||
// (actually, moved to server. do we still need this starting_pos thing?)
|
||||
if(io_type == IO_CLIENT) {
|
||||
if(scenario != &starting_pos) {
|
||||
starting_pos = *scenario;
|
||||
scenario = &starting_pos;
|
||||
}
|
||||
}
|
||||
|
||||
config::const_child_itors story = scenario->child_range("story");
|
||||
//TODO: remove once scenario in carryover_info/gamedata is confirmed
|
||||
// gamestate.classification().next_scenario = (*scenario)["next_scenario"].str();
|
||||
|
||||
bool save_game_after_scenario = true;
|
||||
|
||||
|
@ -423,37 +293,30 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
|
|||
// Preserve old label eg. replay
|
||||
if (gamestate.classification().label.empty()) {
|
||||
if (gamestate.classification().abbrev.empty())
|
||||
gamestate.classification().label = (*scenario)["name"].str();
|
||||
gamestate.classification().label = starting_pos["name"].str();
|
||||
else {
|
||||
gamestate.classification().label = gamestate.classification().abbrev;
|
||||
gamestate.classification().label.append("-");
|
||||
gamestate.classification().label.append((*scenario)["name"]);
|
||||
gamestate.classification().label.append(starting_pos["name"]);
|
||||
}
|
||||
}
|
||||
|
||||
// If the entire scenario should be randomly generated
|
||||
if((*scenario)["scenario_generation"] != "") {
|
||||
generate_scenario(scenario);
|
||||
}
|
||||
std::string map_data = (*scenario)["map_data"];
|
||||
if(map_data.empty() && (*scenario)["map"] != "") {
|
||||
map_data = read_map((*scenario)["map"]);
|
||||
}
|
||||
|
||||
// If the map should be randomly generated
|
||||
if(map_data.empty() && (*scenario)["map_generation"] != "") {
|
||||
generate_map(scenario);
|
||||
}
|
||||
gamestate.expand_random_scenario();
|
||||
//In case this an mp scenario reloaded by sp this was not already done yet.
|
||||
//We don't need to expand [option]s because [variables] are persitent
|
||||
gamestate.expand_mp_events();
|
||||
|
||||
sound::empty_playlist();
|
||||
|
||||
switch (io_type){
|
||||
case IO_NONE:
|
||||
res = playsingle_scenario(game_config, scenario, disp, gamestate, story, skip_replay, end_level);
|
||||
#if !defined(ALWAYS_USE_MP_CONTROLLER)
|
||||
res = playsingle_scenario(game_config, disp, gamestate, story, skip_replay, end_level);
|
||||
break;
|
||||
#endif
|
||||
case IO_SERVER:
|
||||
case IO_CLIENT:
|
||||
res = playmp_scenario(game_config, scenario, disp, gamestate, story, skip_replay, blindfold_replay, io_type, end_level);
|
||||
res = playmp_scenario(game_config, disp, gamestate, story, skip_replay, blindfold_replay, io_type, end_level);
|
||||
break;
|
||||
}
|
||||
} catch(game::load_game_failed& e) {
|
||||
|
@ -493,18 +356,15 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
|
|||
save.save_game_automatic(disp.video(), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gamestate.convert_to_start_save();
|
||||
recorder.clear();
|
||||
gamestate.replay_data.clear();
|
||||
gamestate.replay_start().clear();
|
||||
|
||||
// On DEFEAT, QUIT, or OBSERVER_END, we're done now
|
||||
//if(res == QUIT || ((res != VICTORY) && gamestate.carryover_sides_start["next_scenario"].empty()))
|
||||
|
||||
//If there is no next scenario we're done now.
|
||||
if(res == QUIT || !end_level.proceed_to_next_level || gamestate.carryover_sides_start["next_scenario"].empty())
|
||||
{
|
||||
gamestate.snapshot = config();
|
||||
return res;
|
||||
}
|
||||
else if(res == OBSERVER_END)
|
||||
|
@ -514,7 +374,6 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
|
|||
gui2::tmessage::yes_no_buttons);
|
||||
|
||||
if(dlg_res == gui2::twindow::CANCEL) {
|
||||
gamestate.snapshot = config();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -524,77 +383,57 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
|
|||
if (!end_level.prescenario_save)
|
||||
save_game_after_scenario = false;
|
||||
|
||||
//TODO: remove once scenario in carryover_info/gamedata is confirmed
|
||||
// Switch to the next scenario.
|
||||
//gamestate.classification().scenario = gamestate.classification().next_scenario;
|
||||
|
||||
sides = carryover_info(gamestate.carryover_sides_start);
|
||||
sides.rng().rotate_random();
|
||||
gamestate.carryover_sides_start = sides.to_config();
|
||||
|
||||
if (io_type == IO_CLIENT) {
|
||||
// Opens mp::connect dialog to get a new gamestate.
|
||||
mp::ui::result wait_res = mp::goto_mp_wait(gamestate, disp,
|
||||
game_config, res == OBSERVER_END);
|
||||
if (wait_res == mp::ui::QUIT) {
|
||||
gamestate.snapshot = config();
|
||||
return QUIT;
|
||||
}
|
||||
|
||||
starting_pos = gamestate.replay_start();
|
||||
gamestate = saved_game(starting_pos);
|
||||
//The host shoudl send teh complete savegame now that also contains teh carryvoer seides start-
|
||||
//gamestate.set_scenario(gamestate.replay_start());
|
||||
//gamestate.replay_start() = config();
|
||||
// Retain carryover_sides_start, as the config from the server
|
||||
// doesn't contain it.
|
||||
gamestate.carryover_sides_start = sides.to_config();
|
||||
//TODO: enable this again or make mp_wait not change carryover sides start.
|
||||
//gamestate.carryover_sides_start = sides.to_config();
|
||||
} else {
|
||||
// Retrieve next scenario data.
|
||||
scenario = &game_config.find_child(campaign_type_str, "id",
|
||||
gamestate.carryover_sides_start["next_scenario"]);
|
||||
if (!*scenario) {
|
||||
scenario = NULL;
|
||||
} else {
|
||||
starting_pos = *scenario;
|
||||
scenario = &starting_pos;
|
||||
}
|
||||
|
||||
if (io_type == IO_SERVER && scenario != NULL) {
|
||||
mp_game_settings& params = gamestate.mp_settings();
|
||||
gamestate.expand_scenario();
|
||||
|
||||
if (io_type == IO_SERVER && gamestate.valid()) {
|
||||
// A hash have to be generated using an unmodified
|
||||
// scenario data.
|
||||
params.hash = scenario->hash();
|
||||
gamestate.mp_settings().hash = starting_pos.hash();
|
||||
|
||||
// Apply carryover before passing a scenario data to the
|
||||
// mp::connect_engine.
|
||||
team_init(starting_pos, gamestate);
|
||||
|
||||
//WHY???
|
||||
//gamestate.expand_carryover();
|
||||
|
||||
//We don't merge WML until start of next scenario, but if we want to allow user to disable MP ui in transition,
|
||||
//then we have to move "allow_new_game" attribute over now.
|
||||
bool allow_new_game_flag = (*scenario)["allow_new_game"].to_bool(true);
|
||||
bool allow_new_game_flag = starting_pos["allow_new_game"].to_bool(true);
|
||||
|
||||
if (gamestate.carryover_sides_start.child_or_empty("end_level_data").child_or_empty("next_scenario_settings").has_attribute("allow_new_game")) {
|
||||
allow_new_game_flag = gamestate.carryover_sides_start.child_or_empty("end_level_data").child("next_scenario_settings")["allow_new_game"].to_bool();
|
||||
}
|
||||
|
||||
params.scenario_data = *scenario;
|
||||
params.scenario_data["next_underlying_unit_id"] = n_unit::id_manager::instance().get_save_id();
|
||||
params.mp_scenario = (*scenario)["id"].str();
|
||||
params.mp_scenario_name = (*scenario)["name"].str();
|
||||
params.num_turns = (*scenario)["turns"].to_int(-1);
|
||||
params.saved_game = false;
|
||||
params.use_map_settings =
|
||||
(*scenario)["force_lock_settings"].to_bool();
|
||||
gamestate.mp_settings().num_turns = starting_pos["turns"].to_int(-1);
|
||||
gamestate.mp_settings().saved_game = false;
|
||||
gamestate.mp_settings().use_map_settings = starting_pos["force_lock_settings"].to_bool();
|
||||
|
||||
mp::connect_engine_ptr
|
||||
connect_engine(new mp::connect_engine(disp, gamestate,
|
||||
params, !network_game, false));
|
||||
connect_engine(new mp::connect_engine(gamestate,
|
||||
!network_game, false));
|
||||
|
||||
if (allow_new_game_flag || (game_config::debug && network::nconnections() == 0)) {
|
||||
// Opens mp::connect dialog to allow users to
|
||||
// make an adjustments for scenario.
|
||||
// TODO: Fix this so that it works when network::nconnections() > 0 as well.
|
||||
mp::ui::result connect_res = mp::goto_mp_connect(disp,
|
||||
*connect_engine, game_config, params.name);
|
||||
*connect_engine, game_config, gamestate.mp_settings().name);
|
||||
if (connect_res == mp::ui::QUIT) {
|
||||
return QUIT;
|
||||
}
|
||||
|
@ -603,39 +442,24 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
|
|||
connect_engine->
|
||||
start_game(mp::connect_engine::FORCE_IMPORT_USERS);
|
||||
}
|
||||
}
|
||||
else if (io_type == IO_NONE && gamestate.valid())
|
||||
{
|
||||
//In case this an mp scenario reloaded by sp this was not already done yet.
|
||||
//We don't need to expand [option]s because [variables] are persitent
|
||||
gamestate.expand_mp_events();
|
||||
|
||||
starting_pos = gamestate.replay_start();
|
||||
scenario = &starting_pos;
|
||||
|
||||
// TODO: move this code to mp::connect_engine
|
||||
// in order to send generated data to the network
|
||||
// before starting the game.
|
||||
//
|
||||
// If the entire scenario should be randomly generated
|
||||
/*if((*scenario)["scenario_generation"] != "") {
|
||||
generate_scenario(scenario);
|
||||
}
|
||||
|
||||
std::string map_data = (*scenario)["map_data"];
|
||||
if(map_data.empty() && (*scenario)["map"] != "") {
|
||||
map_data = read_map((*scenario)["map"]);
|
||||
}
|
||||
|
||||
// If the map should be randomly generated
|
||||
if(map_data.empty() && (*scenario)["map_generation"] != "") {
|
||||
generate_map(scenario);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
if(scenario != NULL) {
|
||||
if(gamestate.valid()) {
|
||||
// Update the label
|
||||
if (gamestate.classification().abbrev.empty())
|
||||
gamestate.classification().label = (*scenario)["name"].str();
|
||||
gamestate.classification().label = starting_pos["name"].str();
|
||||
else {
|
||||
gamestate.classification().label = gamestate.classification().abbrev;
|
||||
gamestate.classification().label.append("-");
|
||||
gamestate.classification().label.append((*scenario)["name"]);
|
||||
gamestate.classification().label.append(starting_pos["name"]);
|
||||
}
|
||||
|
||||
// If this isn't the last scenario, then save the game
|
||||
|
@ -654,7 +478,6 @@ LEVEL_RESULT play_game(game_display& disp, saved_game& gamestate,
|
|||
}
|
||||
|
||||
}
|
||||
gamestate.snapshot = config();
|
||||
}
|
||||
|
||||
if (!gamestate.carryover_sides_start["next_scenario"].empty() && gamestate.carryover_sides_start["next_scenario"] != "null") {
|
||||
|
|
|
@ -623,6 +623,7 @@ void playmp_controller::do_idle_notification()
|
|||
|
||||
void playmp_controller::maybe_linger()
|
||||
{
|
||||
linger_ = true;
|
||||
if (!get_end_level_data_const().transient.linger_mode) {
|
||||
if(!is_host()) {
|
||||
// If we continue without lingering we need to
|
||||
|
|
|
@ -343,7 +343,8 @@ void playsingle_controller::report_victory(
|
|||
|
||||
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(gamestate_.snapshot.child_or_empty("variables")["turn_number"].to_int(-1)<1){
|
||||
if(gamestate_.replay_start().empty())
|
||||
{
|
||||
gamestate_.replay_start() = to_config();
|
||||
}
|
||||
HANDLE_END_PLAY_SIGNAL( fire_preload() );
|
||||
|
@ -403,7 +404,7 @@ possible_end_play_signal playsingle_controller::play_scenario_main_loop(end_leve
|
|||
// if we loaded a save file in linger mode, skip to it.
|
||||
if (linger_) {
|
||||
//determine the bonus gold handling for this scenario
|
||||
end_level.read(level_.child_or_empty("endlevel"));
|
||||
end_level.read(level_.child_or_empty("end_level_data"));
|
||||
end_level.transient.carryover_report = false;
|
||||
end_level.transient.disabled = true;
|
||||
end_level_struct els = { SKIP_TO_LINGER };
|
||||
|
@ -497,7 +498,7 @@ LEVEL_RESULT playsingle_controller::play_scenario(
|
|||
if (gameboard_.teams().empty())
|
||||
{
|
||||
//store persistent teams
|
||||
gamestate_.snapshot = config();
|
||||
gamestate_.set_snapshot(config());
|
||||
|
||||
return VICTORY; // this is probably only a story scenario, i.e. has its endlevel in the prestart event
|
||||
}
|
||||
|
@ -565,10 +566,11 @@ LEVEL_RESULT playsingle_controller::play_scenario(
|
|||
}
|
||||
|
||||
// Add all the units that survived the scenario.
|
||||
// this function doesn't move unit to the recalllist anymore i just keep this name to prevent merging conflicts.
|
||||
LOG_NG << "Add units that survived the scenario to the recall list.\n";
|
||||
gameboard_.all_survivors_to_recall();
|
||||
|
||||
gamestate_.snapshot = config();
|
||||
gamestate_.remove_snapshot();
|
||||
if(!is_observer()) {
|
||||
persist_.end_transaction();
|
||||
}
|
||||
|
@ -579,7 +581,7 @@ LEVEL_RESULT playsingle_controller::play_scenario(
|
|||
{
|
||||
LOG_NG << "resuming from loaded linger state...\n";
|
||||
//as carryover information is stored in the snapshot, we have to re-store it after loading a linger state
|
||||
gamestate_.snapshot = config();
|
||||
gamestate_.set_snapshot(config());
|
||||
if(!is_observer()) {
|
||||
persist_.end_transaction();
|
||||
}
|
||||
|
@ -1126,6 +1128,8 @@ bool playsingle_controller::is_host() const
|
|||
|
||||
void playsingle_controller::maybe_linger()
|
||||
{
|
||||
//Make sure [end_level_data] gets writen into the snapshot even when skipping linger mode.
|
||||
linger_ = true;
|
||||
if (get_end_level_data_const().transient.linger_mode) {
|
||||
linger();
|
||||
}
|
||||
|
|
|
@ -50,14 +50,12 @@ LEVEL_RESULT play_replay_level(const config& game_config,
|
|||
{
|
||||
const int ticks = SDL_GetTicks();
|
||||
|
||||
config init_level = state_of_game.replay_start();
|
||||
|
||||
DBG_NG << "creating objects... " << (SDL_GetTicks() - ticks) << std::endl;
|
||||
|
||||
boost::scoped_ptr<replay_controller> rc;
|
||||
|
||||
try {
|
||||
rc.reset(new replay_controller(init_level, state_of_game, ticks, game_config, video));
|
||||
rc.reset(new replay_controller(state_of_game.get_replay_starting_pos(), state_of_game, ticks, game_config, video));
|
||||
} catch (end_level_exception & e){
|
||||
return e.result;
|
||||
} catch (end_turn_exception &) {
|
||||
|
|
|
@ -397,7 +397,8 @@ save_info create_save_info::operator()(const std::string& filename) const
|
|||
void extract_summary_from_config(config& cfg_save, config& cfg_summary)
|
||||
{
|
||||
const config &cfg_snapshot = cfg_save.child("snapshot");
|
||||
const config &cfg_replay_start = cfg_save.child("replay_start");
|
||||
//Servergenerated replays contain [scenario] and no [replay_start]
|
||||
const config &cfg_replay_start = cfg_save.child("replay_start") ? cfg_save.child("replay_start") : cfg_save.child("scenario") ;
|
||||
|
||||
const config &cfg_replay = cfg_save.child("replay");
|
||||
const bool has_replay = cfg_replay && !cfg_replay.empty();
|
||||
|
|
|
@ -1,14 +1,55 @@
|
|||
/**
|
||||
Some information about savefiles:
|
||||
A saveile can contain:
|
||||
* General information (toplevel atributes, [multiplayer])
|
||||
This is present in all savefiles
|
||||
* [statistics]
|
||||
This is present in all savefiles but it's not handled by playcampaign/play_controller/saved_game.
|
||||
It's handled by savegame.cpp
|
||||
* [snapshot]
|
||||
If a savegame was saved during a scenaio this contzaings a snapshot of teh game at the point when it was saved.
|
||||
* [carryover_sides_start]
|
||||
At start-of-scenrio saves this contains data from the previous scenario that was preserved
|
||||
* [carryover_sides]
|
||||
In savefile made during the game, this tag contains data from [carryover_sides_start] that was not used in the current scenario but should be saved for a next scenario
|
||||
* [replay_start]
|
||||
A snapshot made very early to replay the game from.
|
||||
* [replay]
|
||||
A record of game actions that was made between the creation of [replay_start] and [snapshot].
|
||||
|
||||
|
||||
|
||||
The following types of savegames are known:
|
||||
* Start of scenario savefiles
|
||||
These files only contain general information, statistics, and [carryover_sides_start]
|
||||
When these saves are loaded the scenario is loaded form teh game config by the next_scenario attribute from [carryover_sides_start]
|
||||
* Expanded Start of scenario savefiles
|
||||
Similar to normal Start-of-scenario savefiles, but the also contain a [scenario] that contins the scenario
|
||||
This type is only used internaly and usualy doesn't get written to the disk.
|
||||
* Ingame savefile
|
||||
These files contain genral information, statistics, [snapshot], [replay], [replay_start], [snapshot], [carryover_sides]
|
||||
Thedse files don't contain a [carryover_sides_start] because both starting points ([replay_start] and [snapshot])
|
||||
were made after [carryover_sides_start] was merged into the scenario.
|
||||
* Replay savefiles
|
||||
Like a Ingame save made durign linger mode, but without the [snapshot]
|
||||
*/
|
||||
|
||||
#include "saved_game.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include "carryover.hpp"
|
||||
#include "cursor.hpp"
|
||||
#include "log.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "game_config_manager.hpp"
|
||||
#include "generators/map_create.hpp"
|
||||
#include "statistics.hpp"
|
||||
#include "serialization/binary_or_text.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <boost/range/adaptors.hpp>
|
||||
#include <boost/range/algorithm.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <cassert>
|
||||
|
||||
static lg::log_domain log_engine("engine");
|
||||
#define ERR_NG LOG_STREAM(err, log_engine)
|
||||
|
@ -16,37 +57,55 @@ static lg::log_domain log_engine("engine");
|
|||
#define LOG_NG LOG_STREAM(info, log_engine)
|
||||
#define DBG_NG LOG_STREAM(debug, log_engine)
|
||||
|
||||
static lg::log_domain log_enginerefac("enginerefac");
|
||||
#define LOG_RG LOG_STREAM(info, log_enginerefac)
|
||||
saved_game::saved_game()
|
||||
: replay_data()
|
||||
, carryover_sides()
|
||||
, carryover_sides_start(carryover_info().to_config())
|
||||
, replay_start_()
|
||||
, classification_()
|
||||
, mp_settings_()
|
||||
, starting_pos_type_(STARTINGPOS_NONE)
|
||||
, starting_pos_()
|
||||
{
|
||||
|
||||
saved_game::saved_game() :
|
||||
replay_data(),
|
||||
snapshot(),
|
||||
carryover_sides(),
|
||||
carryover_sides_start(carryover_info().to_config()),
|
||||
replay_start_(),
|
||||
classification_(),
|
||||
mp_settings_()
|
||||
{}
|
||||
}
|
||||
|
||||
saved_game::saved_game(const config& cfg)
|
||||
: replay_data()
|
||||
, snapshot()
|
||||
, carryover_sides()
|
||||
, carryover_sides_start()
|
||||
, replay_start_()
|
||||
, classification_(cfg)
|
||||
, mp_settings_(cfg)
|
||||
, starting_pos_type_(STARTINGPOS_NONE)
|
||||
, starting_pos_()
|
||||
|
||||
{
|
||||
log_scope("read_game");
|
||||
|
||||
|
||||
carryover_sides = cfg.child_or_empty("carryover_sides");
|
||||
carryover_sides_start = cfg.child_or_empty("carryover_sides_start");
|
||||
|
||||
//Serversided replays can contain multiple [replay]
|
||||
replay_start_ = cfg.child_or_empty("replay_start");
|
||||
replay_data = cfg.child_or_empty("replay");
|
||||
snapshot = cfg.child_or_empty("snapshot");
|
||||
replay_data = config(); //cfg.child_or_empty("replay");
|
||||
BOOST_FOREACH(const config& replay, cfg.child_range("replay"))
|
||||
{
|
||||
replay_data.append_children(replay);
|
||||
}
|
||||
|
||||
if(const config& snapshot = cfg.child("snapshot"))
|
||||
{
|
||||
this->starting_pos_type_ = STARTINGPOS_SNAPSHOT;
|
||||
this->starting_pos_ = snapshot;
|
||||
}
|
||||
else if(const config& scenario = cfg.child("scenario"))
|
||||
{
|
||||
this->starting_pos_type_ = STARTINGPOS_SCENARIO;
|
||||
this->starting_pos_ = scenario;
|
||||
}
|
||||
|
||||
if(snapshot.empty() && carryover_sides_start.empty() && !carryover_sides.empty())
|
||||
if(starting_pos_.empty() && carryover_sides_start.empty() && !carryover_sides.empty())
|
||||
{
|
||||
//Explain me: when could this happen?
|
||||
//if we are loading a start of scenario save and don't have carryover_sides_start, use carryover_sides
|
||||
|
@ -62,15 +121,17 @@ saved_game::saved_game(const config& cfg)
|
|||
|
||||
}
|
||||
|
||||
saved_game::saved_game(const saved_game& state) :
|
||||
replay_data(state.replay_data),
|
||||
snapshot(state.snapshot),
|
||||
carryover_sides(state.carryover_sides),
|
||||
carryover_sides_start(state.carryover_sides_start),
|
||||
replay_start_(state.replay_start_),
|
||||
classification_(state.classification_),
|
||||
mp_settings_(state.mp_settings_)
|
||||
{}
|
||||
saved_game::saved_game(const saved_game& state)
|
||||
: replay_data(state.replay_data)
|
||||
, carryover_sides(state.carryover_sides)
|
||||
, carryover_sides_start(state.carryover_sides_start)
|
||||
, replay_start_(state.replay_start_)
|
||||
, classification_(state.classification_)
|
||||
, mp_settings_(state.mp_settings_)
|
||||
, starting_pos_type_(state.starting_pos_type_)
|
||||
, starting_pos_(state.starting_pos_)
|
||||
{
|
||||
}
|
||||
|
||||
saved_game& saved_game::operator=(const saved_game& state)
|
||||
{
|
||||
|
@ -82,11 +143,353 @@ saved_game& saved_game::operator=(const saved_game& state)
|
|||
return *this ;
|
||||
}
|
||||
|
||||
|
||||
void saved_game::write_config(config_writer& out) const
|
||||
{
|
||||
write_general_info(out);
|
||||
write_starting_pos(out);
|
||||
if(!this->replay_start_.empty())
|
||||
{
|
||||
out.write_child("replay_start", replay_start_);
|
||||
}
|
||||
if(!this->replay_data.empty())
|
||||
{
|
||||
out.write_child("replay", replay_data);
|
||||
}
|
||||
write_carryover(out);
|
||||
}
|
||||
|
||||
void saved_game::write_starting_pos(config_writer& out) const
|
||||
{
|
||||
if(starting_pos_type_ == STARTINGPOS_SNAPSHOT)
|
||||
{
|
||||
out.write_child("snapshot", starting_pos_);
|
||||
}
|
||||
else if(starting_pos_type_ == STARTINGPOS_SCENARIO)
|
||||
{
|
||||
out.write_child("scenario", starting_pos_);
|
||||
}
|
||||
}
|
||||
void saved_game::write_carryover(config_writer& out) const
|
||||
{
|
||||
assert(not_corrupt());
|
||||
if(!this->carryover_sides.empty())
|
||||
{
|
||||
out.write_child("carryover_sides", carryover_sides);
|
||||
}
|
||||
if(!this->carryover_sides_start.empty())
|
||||
{
|
||||
out.write_child("carryover_sides_start", carryover_sides_start);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void saved_game::write_general_info(config_writer& out) const
|
||||
{
|
||||
out.write(classification_.to_config());
|
||||
if (classification_.campaign_type == game_classification::MULTIPLAYER) {
|
||||
out.write_child(lexical_cast<std::string>(game_classification::MULTIPLAYER), mp_settings_.to_config());
|
||||
out.write_child("multiplayer", mp_settings_.to_config());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void saved_game::expand_scenario()
|
||||
{
|
||||
if(this->starting_pos_type_ == STARTINGPOS_NONE && !this->carryover_sides_start.empty())
|
||||
{
|
||||
resources::config_manager->load_game_config_for_game(this->classification());
|
||||
const config& game_config = resources::config_manager->game_config();
|
||||
const config& scenario = game_config.find_child(lexical_cast_default<std::string> (classification().campaign_type), "id", carryover_sides_start["next_scenario"]);
|
||||
if(scenario)
|
||||
{
|
||||
this->starting_pos_type_ = STARTINGPOS_SCENARIO;
|
||||
this->starting_pos_ = scenario;
|
||||
|
||||
//Set this default value immideately after reading the scenario is importent because otherwise
|
||||
//we might endup settings this value to the multiplayer players name, which would break carryover.
|
||||
//(doing this in at config loading in game_config would be ok too i think.)
|
||||
BOOST_FOREACH(config& side, starting_pos_.child_range("side"))
|
||||
{
|
||||
if(side["save_id"].str() == "")
|
||||
{
|
||||
side["save_id"] = side["id"];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->starting_pos_type_ = STARTINGPOS_INVALID;
|
||||
this->starting_pos_ = config();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//helper objects for saved_game::expand_mp_events()
|
||||
struct modevents_entry
|
||||
{
|
||||
modevents_entry(const std::string& _type, const std::string& _id) : type(_type), id(_id) {}
|
||||
std::string type;
|
||||
std::string id;
|
||||
};
|
||||
struct modevents_entry_for
|
||||
{
|
||||
//this typedef is used by boost.
|
||||
typedef modevents_entry result_type;
|
||||
modevents_entry_for(const std::string& type ) : type_(type) {}
|
||||
modevents_entry operator()(const std::string& id) const
|
||||
{
|
||||
return modevents_entry(type_, id);
|
||||
}
|
||||
private:
|
||||
std::string type_;
|
||||
};
|
||||
|
||||
void saved_game::expand_mp_events()
|
||||
{
|
||||
expand_scenario();
|
||||
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO && !this->starting_pos_["has_mod_events"].to_bool(false))
|
||||
{
|
||||
std::vector<modevents_entry> mods;
|
||||
|
||||
boost::copy( mp_settings_.active_mods
|
||||
| boost::adaptors::transformed(modevents_entry_for("modification"))
|
||||
, std::back_inserter(mods) );
|
||||
if(mp_settings_.mp_era != "") //We don't want the error message below if there is no era (= if this is a sp game)
|
||||
{ mods.push_back(modevents_entry("era", mp_settings_.mp_era)); }
|
||||
|
||||
BOOST_FOREACH(modevents_entry& mod, mods)
|
||||
{
|
||||
if(const config& cfg = resources::config_manager->
|
||||
game_config().find_child(mod.type, "id", mod.id))
|
||||
{
|
||||
BOOST_FOREACH(const config& modevent, cfg.child_range("event"))
|
||||
{
|
||||
this->starting_pos_.add_child("event", modevent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//TODO: A user message instead?
|
||||
ERR_NG << "Couldn't find [" << mod.type<< "] with id=" << mod.id <<std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
this->starting_pos_["has_mod_events"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void saved_game::expand_mp_options()
|
||||
{
|
||||
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO && !this->carryover_sides_start.empty())
|
||||
{
|
||||
std::vector<modevents_entry> mods;
|
||||
|
||||
boost::copy( mp_settings_.active_mods
|
||||
| boost::adaptors::transformed(modevents_entry_for("modification"))
|
||||
, std::back_inserter(mods) );
|
||||
mods.push_back(modevents_entry("era", mp_settings_.mp_era));
|
||||
mods.push_back(modevents_entry("multiplayer", get_scenario_id()));
|
||||
|
||||
config& variables = this->carryover_sides_start.child_or_add("variables");
|
||||
BOOST_FOREACH(modevents_entry& mod, mods)
|
||||
{
|
||||
if(const config& cfg = this->mp_settings().options.find_child(mod.type, "id", mod.id))
|
||||
{
|
||||
BOOST_FOREACH(const config& option, cfg.child_range("option"))
|
||||
{
|
||||
variables[option["id"]] = option["value"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_NG << "Couldn't find [" << mod.type<< "] with id=" << mod.id << " for [option]s" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saved_game::expand_random_scenario()
|
||||
{
|
||||
expand_scenario();
|
||||
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO)
|
||||
{
|
||||
// If the entire scenario should be randomly generated
|
||||
if(starting_pos_["scenario_generation"] != "")
|
||||
{
|
||||
LOG_NG << "randomly generating scenario...\n";
|
||||
const cursor::setter cursor_setter(cursor::WAIT);
|
||||
|
||||
starting_pos_ = random_generate_scenario(starting_pos_["scenario_generation"],
|
||||
starting_pos_.child("generator"));
|
||||
}
|
||||
//it looks like we support a map= where map=filename equals more or less map_data={filename}
|
||||
if(starting_pos_["map_data"].empty() && starting_pos_["map"] != "") {
|
||||
starting_pos_["map_data"] = read_map(starting_pos_["map"]);
|
||||
}
|
||||
// If the map should be randomly generated
|
||||
// We dont want that we accidently to this twice so we check for starting_pos_["map_data"].empty()
|
||||
if(starting_pos_["map_data"].empty() && starting_pos_["map_generation"] != "") {
|
||||
LOG_NG << "randomly generating map...\n";
|
||||
const cursor::setter cursor_setter(cursor::WAIT);
|
||||
|
||||
starting_pos_["map_data"] = random_generate_map(
|
||||
starting_pos_["map_generation"], starting_pos_.child("generator"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saved_game::expand_carryover()
|
||||
{
|
||||
expand_scenario();
|
||||
if(this->starting_pos_type_ == STARTINGPOS_SCENARIO && !this->carryover_sides_start.empty())
|
||||
{
|
||||
//TODO: Add events from modifications and modifications in side [mulitplayer][options][/options][/mulitplayer]
|
||||
|
||||
carryover_info sides(carryover_sides_start);
|
||||
|
||||
sides.transfer_to(get_starting_pos());
|
||||
BOOST_FOREACH(config& side_cfg, get_starting_pos().child_range("side")){
|
||||
sides.transfer_all_to(side_cfg);
|
||||
}
|
||||
|
||||
carryover_sides = sides.to_config();
|
||||
carryover_sides_start = config();
|
||||
}
|
||||
}
|
||||
|
||||
bool saved_game::valid()
|
||||
{
|
||||
return this->starting_pos_type_ != STARTINGPOS_INVALID;
|
||||
}
|
||||
|
||||
void saved_game::set_snapshot(const config& snapshot)
|
||||
{
|
||||
this->starting_pos_type_ = STARTINGPOS_SNAPSHOT;
|
||||
this->starting_pos_ = snapshot;
|
||||
}
|
||||
|
||||
void saved_game::set_scenario(const config& scenario)
|
||||
{
|
||||
this->starting_pos_type_ = STARTINGPOS_SCENARIO;
|
||||
this->starting_pos_ = scenario;
|
||||
//By default we treat the game as 'carryover not expanded yet'
|
||||
if(this->carryover_sides.empty())
|
||||
{
|
||||
this->carryover_sides_start.child_or_add("variables");
|
||||
}
|
||||
}
|
||||
|
||||
void saved_game::remove_snapshot()
|
||||
{
|
||||
this->starting_pos_type_ = STARTINGPOS_NONE;
|
||||
this->starting_pos_ = config();
|
||||
}
|
||||
|
||||
config& saved_game::get_starting_pos()
|
||||
{
|
||||
return starting_pos_;
|
||||
}
|
||||
|
||||
|
||||
const config& saved_game::get_replay_starting_pos()
|
||||
{
|
||||
if(!this->replay_start_.empty())
|
||||
{
|
||||
return replay_start_;
|
||||
}
|
||||
if(!this->carryover_sides_start.empty())
|
||||
{
|
||||
//Try to load the scenario form game config or from [scenario] if there is no [replay_start]
|
||||
expand_scenario();
|
||||
expand_carryover();
|
||||
}
|
||||
if(starting_pos_type_ == STARTINGPOS_SCENARIO)
|
||||
{
|
||||
return starting_pos_;
|
||||
}
|
||||
return this->replay_start_.child("some_non_existet_invalid");
|
||||
}
|
||||
|
||||
void saved_game::remove_old_scenario()
|
||||
{
|
||||
remove_snapshot();
|
||||
carryover_sides = config();
|
||||
replay_data = config();
|
||||
replay_start_ = config();
|
||||
}
|
||||
|
||||
void saved_game::convert_to_start_save()
|
||||
{
|
||||
assert(starting_pos_type_ == STARTINGPOS_SNAPSHOT);
|
||||
carryover_info sides(starting_pos_, true);
|
||||
sides.merge_old_carryover(carryover_info(carryover_sides));
|
||||
sides.rng().rotate_random();
|
||||
carryover_sides_start = sides.to_config();
|
||||
replay_data = config();
|
||||
replay_start_ = config();
|
||||
carryover_sides = config();
|
||||
remove_snapshot();
|
||||
}
|
||||
|
||||
config saved_game::to_config()
|
||||
{
|
||||
//TODO: remove this code dublication with write_... functions.
|
||||
config r = classification_.to_config();
|
||||
if(!this->replay_start_.empty())
|
||||
{
|
||||
r.add_child("replay_start", replay_start_);
|
||||
}
|
||||
if(!this->replay_data.empty())
|
||||
{
|
||||
r.add_child("replay", replay_data);
|
||||
}
|
||||
if(starting_pos_type_ == STARTINGPOS_SNAPSHOT)
|
||||
{
|
||||
r.add_child("snapshot", starting_pos_);
|
||||
}
|
||||
else if(starting_pos_type_ == STARTINGPOS_SCENARIO)
|
||||
{
|
||||
r.add_child("scenario", starting_pos_);
|
||||
}
|
||||
if(!this->carryover_sides.empty())
|
||||
{
|
||||
r.add_child("carryover_sides", carryover_sides);
|
||||
}
|
||||
if(!this->carryover_sides_start.empty())
|
||||
{
|
||||
r.add_child("carryover_sides_start", carryover_sides_start);
|
||||
}
|
||||
|
||||
if (classification_.campaign_type == game_classification::MULTIPLAYER) {
|
||||
r.add_child("multiplayer", mp_settings_.to_config());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
std::string saved_game::get_scenario_id()
|
||||
{
|
||||
if(this->starting_pos_type_ == STARTINGPOS_SNAPSHOT
|
||||
|| this->starting_pos_type_ == STARTINGPOS_SCENARIO)
|
||||
{
|
||||
return starting_pos_["id"];
|
||||
}
|
||||
else
|
||||
{
|
||||
return carryover_sides_start["next_scenario"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool saved_game::not_corrupt() const
|
||||
{
|
||||
if(carryover_sides.empty() && carryover_sides_start.empty())
|
||||
{
|
||||
//this case is dangerous but currently not impossible.
|
||||
WRN_NG << "savefile contains neigher [carryover_sides] not [carryover_sides_start]" << std::endl;
|
||||
}
|
||||
// A Scenario can never contain both of them
|
||||
// normal saves have [carryover_sides] start-of-scenario saved have [carryover_sides_start]
|
||||
// the function expand_carryover transforms a start of scenario save to a normal save
|
||||
// the function convert_to_start_save converts a normal save form teh end of the scenaio
|
||||
// to a start-of-scenario save for a next level
|
||||
return carryover_sides.empty() || carryover_sides_start.empty();
|
||||
}
|
||||
|
|
|
@ -4,12 +4,18 @@
|
|||
|
||||
#include "config.hpp"
|
||||
#include "gamestatus.hpp" //game_classification
|
||||
|
||||
class config_writer;
|
||||
|
||||
|
||||
class saved_game
|
||||
{
|
||||
enum STARTING_POS_TYPE
|
||||
{
|
||||
STARTINGPOS_NONE,
|
||||
STARTINGPOS_SNAPSHOT,
|
||||
STARTINGPOS_SCENARIO,
|
||||
STARTINGPOS_INVALID
|
||||
};
|
||||
public:
|
||||
saved_game();
|
||||
saved_game(const saved_game& state);
|
||||
|
@ -17,33 +23,65 @@ public:
|
|||
|
||||
~saved_game(){}
|
||||
saved_game& operator=(const saved_game& state);
|
||||
|
||||
|
||||
//write the config information into a stream (file)
|
||||
void write_config(config_writer& out) const;
|
||||
|
||||
void write_general_info(config_writer& out) const;
|
||||
void write_carryover(config_writer& out) const;
|
||||
void write_starting_pos(config_writer& out) const;
|
||||
config to_config();
|
||||
///Removes everything except [carryover_sides_start]
|
||||
void remove_old_scenario();
|
||||
game_classification& classification() { return classification_; }
|
||||
const game_classification& classification() const { return classification_; }
|
||||
|
||||
/** Multiplayer parameters for this game */
|
||||
mp_game_settings& mp_settings() { return mp_settings_; }
|
||||
const mp_game_settings& mp_settings() const { return mp_settings_; }
|
||||
///copies the content of a [scenario] with the correct id attribute into this object.
|
||||
void expand_scenario();
|
||||
///merges [carryover_sides_start] into [scenario] and saves the rest into [carryover_sides]
|
||||
///Removes [carryover_sides_start] afterwards
|
||||
void expand_carryover();
|
||||
/// adds [event]s from [era] and [modification] into this scenario
|
||||
/// does NOT expand [option]s because variables are persitent anyway to we don't need it
|
||||
/// should be called after expand_scenario() but before expand_carryover()
|
||||
void expand_mp_events();
|
||||
/// adds values of [option]s inte [carryover_sides_start][variables] so that they are applied in the next level.
|
||||
/// Note that since [variabels] are persistent we only use this once at the beginning
|
||||
/// of a campaign but callings it multiple times is no harm eigher
|
||||
void expand_mp_options();
|
||||
/// takes care of generate_map=, generate_scenario=, map= attributes
|
||||
/// This should be called before expanding carryover or mp_events because this might completely replace starting_pos_.
|
||||
void expand_random_scenario();
|
||||
bool valid();
|
||||
void set_snapshot(const config& snapshot);
|
||||
void set_scenario(const config& scenario);
|
||||
void remove_snapshot();
|
||||
|
||||
bool is_mid_game_save()
|
||||
{
|
||||
return starting_pos_type_ == STARTINGPOS_SNAPSHOT;
|
||||
}
|
||||
/// converts a normal savegame form the end of a scenaio to a start-of-scenario savefiel for teh next scenaio,
|
||||
/// The saved_game must contain a [snapshot] made during the linger mode of the last scenaio.
|
||||
void convert_to_start_save();
|
||||
/// retruns from the config from which the replay will be started. Usualy this is [replay_start] but it can also be a [scenario] if no replay_start is present
|
||||
const config& get_replay_starting_pos();
|
||||
/// returns the id of teh curently played scenaio or the id of the next scenaio if this is a between-scenaios-save (also called start-of-scenario) save.
|
||||
std::string get_scenario_id();
|
||||
/// retruns from the config from which teh game will be started. [scenario] or [snapshot] in the file
|
||||
config& get_starting_pos();
|
||||
config& replay_start() { return replay_start_; }
|
||||
const config& replay_start() const { return replay_start_; }
|
||||
|
||||
bool not_corrupt() const;
|
||||
/**
|
||||
* If the game is saved mid-level, we have a series of replay steps
|
||||
* to take the game up to the position it was saved at.
|
||||
*/
|
||||
config replay_data;
|
||||
|
||||
/**
|
||||
* Snapshot of the game's current contents.
|
||||
*
|
||||
* i.e. unless the player selects to view a replay, the game's settings are
|
||||
* read in from this object.
|
||||
*/
|
||||
config snapshot;
|
||||
|
||||
/** The carryover information for all sides*/
|
||||
config carryover_sides;
|
||||
|
||||
|
@ -56,6 +94,16 @@ private:
|
|||
|
||||
game_classification classification_;
|
||||
mp_game_settings mp_settings_;
|
||||
|
||||
|
||||
/**
|
||||
* Snapshot of the game's current contents.
|
||||
*
|
||||
* i.e. unless the player selects to view a replay, the game's settings are
|
||||
* read in from this object.
|
||||
*/
|
||||
STARTING_POS_TYPE starting_pos_type_;
|
||||
config starting_pos_;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -353,8 +353,11 @@ void loadgame::fill_mplevel_config(config& level){
|
|||
|
||||
// If we have a start of scenario MP campaign scenario the snapshot
|
||||
// is empty the starting position contains the wanted info.
|
||||
#if 0
|
||||
const config& start_data = !gamestate_.snapshot.empty() ? gamestate_.snapshot : gamestate_.replay_start();
|
||||
|
||||
#else
|
||||
const config& start_data = gamestate_.get_starting_pos();
|
||||
#endif
|
||||
level.add_child("map", start_data.child_or_empty("map"));
|
||||
level["id"] = start_data["id"];
|
||||
level["name"] = start_data["name"];
|
||||
|
@ -367,7 +370,7 @@ void loadgame::fill_mplevel_config(config& level){
|
|||
level.add_child("multiplayer", gamestate_.mp_settings().to_config());
|
||||
|
||||
//Start-of-scenario save
|
||||
if(gamestate_.snapshot.empty()){
|
||||
if(!gamestate_.is_mid_game_save()){
|
||||
//For a start-of-scenario-save, write the data to the starting_pos and not the snapshot, since
|
||||
//there should only be snapshots for midgame reloads
|
||||
if (config &c = level.child("replay_start")) {
|
||||
|
@ -592,7 +595,7 @@ void savegame::write_game(config_writer &out)
|
|||
out.write_key_val("version", game_config::version);
|
||||
out.write_key_val("next_underlying_unit_id", lexical_cast<std::string>(n_unit::id_manager::instance().get_save_id()));
|
||||
|
||||
gamestate_.write_config(out);
|
||||
gamestate_.write_general_info(out);
|
||||
out.open_child("statistics");
|
||||
statistics::write_stats(out);
|
||||
out.close_child("statistics");
|
||||
|
@ -631,8 +634,7 @@ scenariostart_savegame::scenariostart_savegame(saved_game &gamestate, const comp
|
|||
|
||||
void scenariostart_savegame::write_game(config_writer &out){
|
||||
savegame::write_game(out);
|
||||
|
||||
out.write_child("carryover_sides_start", gamestate().carryover_sides_start);
|
||||
gamestate().write_carryover(out);
|
||||
}
|
||||
|
||||
replay_savegame::replay_savegame(saved_game &gamestate, const compression::format compress_saves)
|
||||
|
@ -652,11 +654,11 @@ void replay_savegame::create_filename()
|
|||
|
||||
void replay_savegame::write_game(config_writer &out) {
|
||||
savegame::write_game(out);
|
||||
|
||||
out.write_child("carryover_sides_start", gamestate().carryover_sides_start);
|
||||
out.write_child("carryover_sides", gamestate().carryover_sides);
|
||||
|
||||
gamestate().write_carryover(out);
|
||||
out.write_child("replay_start", gamestate().replay_start());
|
||||
out.write_child("replay", gamestate().replay_data);
|
||||
|
||||
}
|
||||
|
||||
autosave_savegame::autosave_savegame(saved_game &gamestate,
|
||||
|
@ -715,6 +717,7 @@ ingame_savegame::ingame_savegame(saved_game &gamestate,
|
|||
: savegame(gamestate, compress_saves, _("Save Game")),
|
||||
gui_(gui)
|
||||
{
|
||||
gamestate.set_snapshot(snapshot_cfg);
|
||||
snapshot().merge_with(snapshot_cfg);
|
||||
}
|
||||
|
||||
|
@ -733,10 +736,10 @@ void ingame_savegame::write_game(config_writer &out) {
|
|||
log_scope("write_game");
|
||||
|
||||
savegame::write_game(out);
|
||||
|
||||
gamestate().write_carryover(out);
|
||||
out.write_child("snapshot",snapshot());
|
||||
out.write_child("replay_start", gamestate().replay_start());
|
||||
out.write_child("carryover_sides", gamestate().carryover_sides);
|
||||
out.write_child("carryover_sides_start", gamestate().carryover_sides_start);
|
||||
out.write_child("replay", gamestate().replay_data);
|
||||
}
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ protected:
|
|||
void set_error_message(const std::string& error_message) { error_message_ = error_message; }
|
||||
|
||||
const std::string& title() { return title_; }
|
||||
saved_game& gamestate() { return gamestate_; }
|
||||
const saved_game& gamestate() { return gamestate_; }
|
||||
config& snapshot() { return snapshot_; }
|
||||
|
||||
/** If there needs to be some data fiddling before saving the game, this is the place to go. */
|
||||
|
@ -161,7 +161,7 @@ private:
|
|||
/** Throws game::save_game_failed. */
|
||||
scoped_ostream open_save_game(const std::string &label);
|
||||
friend class save_info;
|
||||
|
||||
//before_save (write replay data) changes this so it cannot be const
|
||||
saved_game& gamestate_;
|
||||
|
||||
/** Gamestate information at the time of saving. Note that this object is needed here, since
|
||||
|
|
|
@ -4026,7 +4026,7 @@ void LuaKernel::initialize()
|
|||
/// elsewhere (in the C++ code).
|
||||
/// Any child tags not in this list will be passed to Lua's on_load event.
|
||||
static char const *handled_file_tags[] = {
|
||||
"color_palette", "color_range", "display", "endlevel", "era",
|
||||
"color_palette", "color_range", "display", "end_level_data", "era",
|
||||
"event", "generator", "label", "lua", "map", "menu_item",
|
||||
"modification", "music", "options", "side", "sound_source",
|
||||
"story", "terrain_graphics", "time", "time_area", "tunnel",
|
||||
|
|
|
@ -94,8 +94,20 @@ game::~game()
|
|||
} catch (...) {}
|
||||
}
|
||||
|
||||
/// returns const so that operator [] won't create empty keys if not existent
|
||||
static const simple_wml::node& get_multiplayer(const simple_wml::node& root)
|
||||
{
|
||||
if(const simple_wml::node* multiplayer = root.child("multiplayer"))
|
||||
return *multiplayer;
|
||||
else
|
||||
{
|
||||
ERR_GAME << "no [multiplayer] found. Returning root\n";
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
bool game::allow_observers() const {
|
||||
return level_["observer"].to_bool(true);
|
||||
return get_multiplayer(level_.root())["observer"].to_bool(true);
|
||||
}
|
||||
|
||||
bool game::is_observer(const network::connection player) const {
|
||||
|
@ -156,7 +168,7 @@ std::string game::list_users(user_vector users, const std::string& func) const
|
|||
}
|
||||
|
||||
void game::perform_controller_tweaks() {
|
||||
const simple_wml::node::child_list & sides = level_.root().children("side");
|
||||
const simple_wml::node::child_list & sides = get_sides_list();
|
||||
|
||||
DBG_GAME << "****\n Performing controller tweaks. sides = " << std::endl;
|
||||
DBG_GAME << debug_sides_info() << std::endl;
|
||||
|
@ -212,8 +224,9 @@ void game::perform_controller_tweaks() {
|
|||
//not to send them at all, although not if it complicates the server code.
|
||||
}
|
||||
|
||||
|
||||
void game::start_game(const player_map::const_iterator starter) {
|
||||
const simple_wml::node::child_list & sides = level_.root().children("side");
|
||||
const simple_wml::node::child_list & sides = get_sides_list();
|
||||
DBG_GAME << "****\n Starting game. sides = " << std::endl;
|
||||
DBG_GAME << debug_sides_info() << std::endl;
|
||||
DBG_GAME << "****" << std::endl;
|
||||
|
@ -221,13 +234,16 @@ void game::start_game(const player_map::const_iterator starter) {
|
|||
|
||||
started_ = true;
|
||||
// Prevent inserting empty keys when reading.
|
||||
const simple_wml::node& s = level_.root();
|
||||
const simple_wml::node& s = get_multiplayer(level_.root());
|
||||
|
||||
const bool save = s["savegame"].to_bool();
|
||||
LOG_GAME << network::ip_address(starter->first) << "\t"
|
||||
<< starter->second.name() << "\t" << "started"
|
||||
<< (save ? " reloaded" : "") << " game:\t\"" << name_ << "\" (" << id_
|
||||
<< ") with: " << list_users(players_, __func__) << ". Settings: map: " << s["id"]
|
||||
<< "\tera: " << (s.child("era") ? (*s.child("era"))["id"] : "")
|
||||
//<< ") with: " << list_users(players_, __func__) << ". Settings: map: " << s["id"]
|
||||
<< ") with: " << list_users(players_, __func__) << ". Settings: map: " << s["mp_scenario"]
|
||||
//<< "\tera: " << (s.child("era") ? (*s.child("era"))["id"] : "")
|
||||
<< "\tera: " << s["mp_era"]
|
||||
<< "\tXP: " << s["experience_modifier"]
|
||||
<< "\tGPV: " << s["mp_village_gold"]
|
||||
<< "\tfog: " << s["mp_fog"]
|
||||
|
@ -305,7 +321,7 @@ bool game::take_side(const player_map::const_iterator user)
|
|||
cfg.root().set_attr("gender", "random");
|
||||
|
||||
// Check if we can figure out a fitting side.
|
||||
const simple_wml::node::child_list& sides = level_.root().children("side");
|
||||
const simple_wml::node::child_list& sides = get_sides_list();
|
||||
for(simple_wml::node::child_list::const_iterator side = sides.begin(); side != sides.end(); ++side) {
|
||||
if(((**side)["controller"] == "network" || (**side)["controller"] == "reserved")
|
||||
&& ((**side)["save_id"] == user->second.name().c_str()
|
||||
|
@ -344,7 +360,7 @@ void game::update_side_data() {
|
|||
players_.clear();
|
||||
observers_.clear();
|
||||
|
||||
const simple_wml::node::child_list& level_sides = level_.root().children("side");
|
||||
const simple_wml::node::child_list& level_sides = get_sides_list();
|
||||
/* This causes data corruption for some reason
|
||||
if (!lg::debug.dont_log(log_server)) {
|
||||
for (simple_wml::node::child_list::const_iterator side = level_sides.begin();
|
||||
|
@ -421,7 +437,7 @@ void game::transfer_side_control(const network::connection sock, const simple_wm
|
|||
return;
|
||||
}
|
||||
|
||||
if (side_num > level_.root().children("side").size()) {
|
||||
if (side_num > get_sides_list().size()) {
|
||||
send_server_message("Invalid side number.", sock);
|
||||
return;
|
||||
}
|
||||
|
@ -577,9 +593,9 @@ bool game::describe_slots() {
|
|||
return false;
|
||||
|
||||
int available_slots = 0;
|
||||
int num_sides = level_.root().children("side").size();
|
||||
int num_sides = get_sides_list().size();
|
||||
int i = 0;
|
||||
const simple_wml::node::child_list& side_list = level_.root().children("side");
|
||||
const simple_wml::node::child_list& side_list = get_sides_list();
|
||||
for(simple_wml::node::child_list::const_iterator it = side_list.begin(); it != side_list.end(); ++it, ++i) {
|
||||
if (((**it)["allow_player"].to_bool(true) == false) || (**it)["controller"] == "null") {
|
||||
num_sides--;
|
||||
|
@ -1265,7 +1281,7 @@ void game::load_next_scenario(const player_map::const_iterator user) {
|
|||
simple_wml::node & next_scen = cfg_scenario.root().add_child("next_scenario");
|
||||
level_.root().copy_into(next_scen);
|
||||
|
||||
const simple_wml::node::child_list & sides = next_scen.children("side");
|
||||
const simple_wml::node::child_list & sides = starting_pos(next_scen)->children("side");
|
||||
|
||||
DBG_GAME << "****\n loading next scenario for a client. sides info = " << std::endl;
|
||||
DBG_GAME << debug_sides_info() << std::endl;
|
||||
|
@ -1334,7 +1350,7 @@ void game::send_data_team(simple_wml::document& data,
|
|||
|
||||
|
||||
bool game::is_on_team(const simple_wml::string_span& team, const network::connection player) const {
|
||||
const simple_wml::node::child_list& side_list = level_.root().children("side");
|
||||
const simple_wml::node::child_list& side_list = get_sides_list();
|
||||
for (side_vector::const_iterator side = sides_.begin(); side != sides_.end(); ++side) {
|
||||
if (*side != player) continue;
|
||||
for (simple_wml::node::child_list::const_iterator i = side_list.begin();
|
||||
|
@ -1454,11 +1470,13 @@ void game::save_replay() {
|
|||
history_.clear();
|
||||
|
||||
std::stringstream name;
|
||||
name << level_["name"] << " Turn " << current_turn();
|
||||
name << (*starting_pos( level_.root()))["name"] << " Turn " << current_turn();
|
||||
|
||||
std::stringstream replay_data;
|
||||
try {
|
||||
#if 0
|
||||
replay_data << "campaign_type=\"multiplayer\"\n"
|
||||
//why did we save difficulcy here ? esp in scmapogn difficulacy = normal is not bguaranteed
|
||||
<< "difficulty=\"NORMAL\"\n"
|
||||
<< "label=\"" << name.str() << "\"\n"
|
||||
<< "mp_game_title=\"" << name_ << "\"\n"
|
||||
|
@ -1469,7 +1487,15 @@ void game::save_replay() {
|
|||
<< replay_commands
|
||||
<< "[/replay]\n"
|
||||
<< "[replay_start]\n" << level_.output() << "[/replay_start]\n";
|
||||
#else
|
||||
replay_data << level_.output()
|
||||
//This can result in having 2 [replay] at toplevel since level_ can contain one already. But the client can handle this (simply merges them).
|
||||
<< "[replay]\n"
|
||||
<< "\t[command]\n\t\t[start]\n\t\t[/start]\n\t[/command]\n" //this is required by gfgtdf's sync mechanism, in PR 121
|
||||
<< replay_commands
|
||||
<< "[/replay]\n";
|
||||
|
||||
#endif
|
||||
name << " (" << id_ << ").bz2";
|
||||
|
||||
std::string replay_data_str = replay_data.str();
|
||||
|
@ -1571,7 +1597,7 @@ std::string game::debug_player_info() const {
|
|||
std::string game::debug_sides_info() const {
|
||||
std::stringstream result;
|
||||
result << "game id: " << id_ << "\n";
|
||||
const simple_wml::node::child_list & sides = level_.root().children("side");
|
||||
const simple_wml::node::child_list & sides = get_sides_list();
|
||||
|
||||
result << "\t\t level, server\n";
|
||||
for(simple_wml::node::child_list::const_iterator s = sides.begin(); s != sides.end(); ++s) {
|
||||
|
|
|
@ -51,7 +51,29 @@ public:
|
|||
|
||||
/** Checks whether the connection's ip address is banned. */
|
||||
bool player_is_banned(const network::connection player) const;
|
||||
bool level_init() const { return level_.child("side") != NULL; }
|
||||
bool level_init() const { return level_.child("snapshot") || level_.child("scenario"); }
|
||||
static simple_wml::node* starting_pos(simple_wml::node& data)
|
||||
{
|
||||
if(simple_wml::node* scenario = data.child("scenario"))
|
||||
return scenario;
|
||||
else if(simple_wml::node* snapshot = data.child("snapshot"))
|
||||
return snapshot;
|
||||
else
|
||||
return &data;
|
||||
}
|
||||
static const simple_wml::node* starting_pos(const simple_wml::node& data)
|
||||
{
|
||||
if(const simple_wml::node* scenario = data.child("scenario"))
|
||||
return scenario;
|
||||
else if(const simple_wml::node* snapshot = data.child("snapshot"))
|
||||
return snapshot;
|
||||
else
|
||||
return &data;
|
||||
}
|
||||
const simple_wml::node::child_list & get_sides_list() const
|
||||
{
|
||||
return starting_pos( level_.root())->children("side");
|
||||
}
|
||||
bool started() const { return started_; }
|
||||
|
||||
size_t nplayers() const { return players_.size(); }
|
||||
|
|
|
@ -2357,12 +2357,13 @@ void server::process_data_game(const network::connection sock,
|
|||
wesnothd::game* g = *itor;
|
||||
|
||||
// If this is data describing the level for a game.
|
||||
if (data.child("side")) {
|
||||
if (data.child("snapshot") || data.child("scenario")) {
|
||||
if (!g->is_owner(sock)) {
|
||||
return;
|
||||
}
|
||||
size_t nsides = 0;
|
||||
const simple_wml::node::child_list& sides = data.root().children("side");
|
||||
const simple_wml::node* starting_pos = wesnothd::game::starting_pos(data.root());
|
||||
const simple_wml::node::child_list& sides = starting_pos->children("side");
|
||||
for (simple_wml::node::child_list::const_iterator s = sides.begin(); s != sides.end(); ++s) {
|
||||
++nsides;
|
||||
}
|
||||
|
@ -2420,7 +2421,7 @@ void server::process_data_game(const network::connection sock,
|
|||
// If there is no shroud, then tell players in the lobby
|
||||
// what the map looks like
|
||||
if (!data["mp_shroud"].to_bool()) {
|
||||
desc.set_attr_dup("map_data", data["map_data"]);
|
||||
desc.set_attr_dup("map_data", (*wesnothd::game::starting_pos(data.root()))["map_data"]);
|
||||
}
|
||||
if (const simple_wml::node* e = data.child("era")) {
|
||||
if (!e->attr("require_era").to_bool(true)) {
|
||||
|
@ -2475,7 +2476,7 @@ void server::process_data_game(const network::connection sock,
|
|||
}
|
||||
g->save_replay();
|
||||
size_t nsides = 0;
|
||||
const simple_wml::node::child_list& sides = scenario->children("side");
|
||||
const simple_wml::node::child_list& sides = wesnothd::game::starting_pos(*scenario)->children("side");
|
||||
for (simple_wml::node::child_list::const_iterator s = sides.begin(); s != sides.end(); ++s) {
|
||||
++nsides;
|
||||
}
|
||||
|
@ -2512,7 +2513,7 @@ void server::process_data_game(const network::connection sock,
|
|||
|
||||
// If there is no shroud, then tell players in the lobby
|
||||
// what the map looks like.
|
||||
const simple_wml::node& s = g->level().root();
|
||||
const simple_wml::node& s = *wesnothd::game::starting_pos(g->level().root());
|
||||
desc.set_attr_dup("map_data", s["mp_shroud"].to_bool() ? "" :
|
||||
s["map_data"]);
|
||||
if (const simple_wml::node* e = data.child("era")) {
|
||||
|
@ -2587,7 +2588,7 @@ void server::process_data_game(const network::connection sock,
|
|||
if (!g->is_owner(sock)) return;
|
||||
g->level().root().apply_diff(*diff);
|
||||
const simple_wml::node* cfg_change = diff->child("change_child");
|
||||
if (cfg_change && cfg_change->child("side")) {
|
||||
if (cfg_change /*&& cfg_change->child("side") itÄ's very likeley that the diff cahnges a side so we dont loost with this check*/) {
|
||||
g->update_side_data();
|
||||
}
|
||||
if (g->describe_slots()) {
|
||||
|
|
|
@ -40,9 +40,8 @@ public:
|
|||
|
||||
class test_mp_connect_engine : public mp::connect_engine {
|
||||
public:
|
||||
test_mp_connect_engine(game_display& disp, saved_game& gamestate,
|
||||
const mp_game_settings& params) :
|
||||
mp::connect_engine(disp, gamestate, params, true, true)
|
||||
test_mp_connect_engine(game_display& /*disp*/, saved_game& gamestate) :
|
||||
mp::connect_engine(gamestate, true, true)
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -52,7 +51,6 @@ public:
|
|||
namespace {
|
||||
|
||||
boost::scoped_ptr<game_display> disp;
|
||||
boost::scoped_ptr<mp_game_settings> params;
|
||||
boost::scoped_ptr<saved_game> state;
|
||||
|
||||
}
|
||||
|
@ -78,15 +76,16 @@ struct mp_connect_fixture {
|
|||
state.reset(new saved_game());
|
||||
state->classification().campaign_type = game_classification::MULTIPLAYER;
|
||||
config_manager->load_game_config_for_game(state->classification());
|
||||
|
||||
state->mp_settings().mp_era = "era_default";
|
||||
state->mp_settings().name = "multiplayer_The_Freelands";
|
||||
state->mp_settings().use_map_settings = true;
|
||||
state->mp_settings().saved_game = false;
|
||||
|
||||
params.reset(new mp_game_settings());
|
||||
params->mp_era = "era_default";
|
||||
params->name = "multiplayer_The_Freelands";
|
||||
params->use_map_settings = true;
|
||||
params->saved_game = false;
|
||||
params->num_turns = params->scenario_data["turns"];
|
||||
params->scenario_data = config_manager->
|
||||
game_config().find_child(lexical_cast<std::string>(game_classification::MULTIPLAYER), "id", params->name);
|
||||
state->set_scenario(config_manager->
|
||||
game_config().find_child(lexical_cast<std::string>(game_classification::MULTIPLAYER), "id", state->mp_settings().name));
|
||||
|
||||
state->mp_settings().num_turns = state->get_starting_pos()["turns"];
|
||||
}
|
||||
~mp_connect_fixture()
|
||||
{
|
||||
|
@ -104,7 +103,7 @@ struct mp_connect_fixture {
|
|||
static test_mp_connect_engine* create_test_mp_connect_engine()
|
||||
{
|
||||
test_mp_connect_engine* mp_connect_engine =
|
||||
new test_mp_connect_engine(*disp, *state, *params);
|
||||
new test_mp_connect_engine(*disp, *state);
|
||||
|
||||
return mp_connect_engine;
|
||||
}
|
||||
|
@ -128,8 +127,8 @@ BOOST_AUTO_TEST_SUITE( mp_connect )
|
|||
BOOST_AUTO_TEST_CASE( flg_map_settings )
|
||||
{
|
||||
// Set up side_engine and its dependencies.
|
||||
params->use_map_settings = true;
|
||||
params->saved_game = false;
|
||||
state->mp_settings().use_map_settings = true;
|
||||
state->mp_settings().saved_game = false;
|
||||
boost::scoped_ptr<test_mp_connect_engine>
|
||||
connect_engine(create_test_mp_connect_engine());
|
||||
mp::side_engine_ptr side_engine;
|
||||
|
@ -339,8 +338,8 @@ BOOST_AUTO_TEST_CASE( flg_map_settings )
|
|||
BOOST_AUTO_TEST_CASE( flg_no_map_settings )
|
||||
{
|
||||
// Set up side_engine and its dependencies.
|
||||
params->use_map_settings = false;
|
||||
params->saved_game = false;
|
||||
state->mp_settings().use_map_settings = false;
|
||||
state->mp_settings().saved_game = false;
|
||||
boost::scoped_ptr<test_mp_connect_engine>
|
||||
connect_engine(create_test_mp_connect_engine());
|
||||
mp::side_engine_ptr side_engine;
|
||||
|
|
Loading…
Add table
Reference in a new issue