From fb960ec58c3547d1caa652aa6f19f4e52643571e Mon Sep 17 00:00:00 2001 From: "Ignacio R. Morelle" Date: Wed, 10 Dec 2008 15:22:02 +0000 Subject: [PATCH] Forward-port 2008-12-01T19:42:47Z!joerg.hinrichs@alice-dsl.de from the 1.4 maintenance branch... to development trunk; hand-applied the diff discarding all the spurious format-only changes, and making the code aware of the changes introduced by revisions 2008-03-30T13:49:03Z!joerg.hinrichs@alice-dsl.de..2008-04-01T21:51:29Z!joerg.hinrichs@alice-dsl.de in trunk. This seems to work well testing up to the end of AToTB:2, with just some "checksum mismatch" warnings that only display on debug mode... --- changelog | 1 + players_changelog | 1 + src/config_adapter.cpp | 2 +- src/gamestatus.cpp | 23 +++++++++++++++++++++++ src/gamestatus.hpp | 15 ++++++++------- src/playcampaign.cpp | 11 ++++++++++- src/playsingle_controller.cpp | 2 ++ src/replay.cpp | 6 ++++++ src/replay.hpp | 1 + 9 files changed, 53 insertions(+), 9 deletions(-) diff --git a/changelog b/changelog index 098c45b54bf..2342f12fc74 100644 --- a/changelog +++ b/changelog @@ -58,6 +58,7 @@ Version 1.5.6+svn: respectively, in [endlevel] or [campaign] tags. end_text_duration is measured in milliseconds. (feature #10449) * Miscellaneous and bug fixes: + * Fixed replays for single-player campaigns (bug #12005). * New memory allocator introduced to the engine. It should produce 5-10% savings in memory usage on 64-bit systems. * Included extra headers for certain g++ versions (patch #1113). diff --git a/players_changelog b/players_changelog index b347b6854de..dcf0aa0d4c6 100644 --- a/players_changelog +++ b/players_changelog @@ -35,6 +35,7 @@ Version 1.5.6+svn: * Increased the cost of the Goblin Spearman from 8 to 9. * Miscellaneous and bugfixes + * Fixed single-player campaign scenario replays. * Fixed random memory corruption/assertion failure/massive memory leak due to story screens. diff --git a/src/config_adapter.cpp b/src/config_adapter.cpp index 38a0e790c77..6bd00896ad0 100644 --- a/src/config_adapter.cpp +++ b/src/config_adapter.cpp @@ -86,7 +86,7 @@ void get_player_info(const config& cfg, game_state& gamestate, scenarios. Snapshots and replays are loaded from savegames and got their own gold information, which must not be altered here */ - if ( (player != NULL) && (!snapshot) && (!replay) ) { + if ( (player != NULL) && (!snapshot) ) { if(player->gold_add) { ngold += player->gold; } else if(player->gold >= ngold) { diff --git a/src/gamestatus.cpp b/src/gamestatus.cpp index 246cc994031..5a9e0014395 100644 --- a/src/gamestatus.cpp +++ b/src/gamestatus.cpp @@ -530,6 +530,17 @@ game_state::game_state(const config& cfg, bool show_replay) : const config* replay_start = cfg.child("replay_start"); if(replay_start != NULL) { starting_pos = *replay_start; + //This is a quick hack to make replays for campaigns work again: + //The [player] information needs to be stored somewhere within the gamestate, + //because we need it later on when creating the replay savegame. + //We therefore put it inside the starting_pos, so it doesn't get lost. + //See also playcampaign::play_game, where after finishing the scenario the replay + //will be saved. + config::child_list player_list = cfg.get_children("player"); + for (config::child_list::const_iterator p = player_list.begin(); p != player_list.end(); p++){ + config& cfg_player = starting_pos.add_child("player"); + cfg_player.merge_with(**p); + } } if(cfg.child("statistics")) { @@ -569,6 +580,18 @@ static void write_player(const player_info& player, config& cfg) cfg["can_recruit"] = can_recruit_str; } +void write_players(game_state& gamestate, config& cfg) +{ + for(std::map::const_iterator i=gamestate.players.begin(); + i!=gamestate.players.end(); ++i) + { + config new_cfg; + write_player(i->second, new_cfg); + new_cfg["save_id"]=i->first; + cfg.add_child("player", new_cfg); + } +} + static void write_player(config_writer &out, const player_info& player) { out.write_key_val("name", player.name); diff --git a/src/gamestatus.hpp b/src/gamestatus.hpp index 8d0b8097c04..e13b441e646 100644 --- a/src/gamestatus.hpp +++ b/src/gamestatus.hpp @@ -102,6 +102,13 @@ public: /** Return the Nth player, or NULL if no such player exists. */ player_info* get_player(const std::string& id); + + /** + * Loads the recall list. + * + * @param players Reference to the players section to load. + */ + void load_recall_list(const config::child_list& players); std::vector scoped_variables; std::map wml_menu_items; @@ -160,13 +167,6 @@ private: mutable config temporaries; // lengths of arrays, etc. const rand_rng::set_random_generator generator_setter; /**< Make sure that rng is initialized first */ friend struct variable_info; - - /** - * Loads the recall list. - * - * @param players Reference to the players section to load. - */ - void load_recall_list(const config::child_list& players); }; /** @@ -316,6 +316,7 @@ enum WRITE_GAME_MODE { WRITE_SNAPSHOT_ONLY, WRITE_FULL_GAME }; void read_save_file(const std::string& name, config& cfg, std::string* error_log); +void write_players(game_state& gamestate, config& cfg); void write_game(const game_state& gamestate, config& cfg, WRITE_GAME_MODE mode=WRITE_FULL_GAME); void write_game(config_writer &out, const game_state& gamestate, WRITE_GAME_MODE mode=WRITE_FULL_GAME); diff --git a/src/playcampaign.cpp b/src/playcampaign.cpp index 54b7ff7e720..c7878d24740 100644 --- a/src/playcampaign.cpp +++ b/src/playcampaign.cpp @@ -416,6 +416,13 @@ LEVEL_RESULT play_game(display& disp, game_state& gamestate, const config& game_ gui::OK_CANCEL, _("Save Replay"), false, false) == 0) { try { config snapshot; + //If the starting position contains player information, use this for + //the replay savegame (this originally comes from the gamestate constructor, + //where the player stuff is added to the starting position to be used here. + config::child_list player_list = gamestate.starting_pos.get_children("player"); + if (player_list.size() > 0) { + recorder.set_save_info(gamestate, player_list); + } recorder.save_game(label, snapshot, gamestate.starting_pos); } catch(game::save_game_failed&) { gui::show_error_message(disp, _("The replay could not be saved")); @@ -506,7 +513,9 @@ LEVEL_RESULT play_game(display& disp, game_state& gamestate, const config& game_ // Sends scenario data config cfg; cfg.add_child("store_next_scenario", *scenario); - + //Add the player section to the starting position so we can get the correct recall list + //when loading the replay later on + write_players(gamestate, gamestate.starting_pos); // Adds player information, and other state // information, to the configuration object assert(cfg.child("store_next_scenario") != NULL); diff --git a/src/playsingle_controller.cpp b/src/playsingle_controller.cpp index 7f03086e4a7..a6016dae232 100644 --- a/src/playsingle_controller.cpp +++ b/src/playsingle_controller.cpp @@ -412,10 +412,12 @@ LEVEL_RESULT playsingle_controller::play_scenario(const std::vector& st } // Add all the units that survived the scenario. + LOG_NG << "Add units that survived the scenario to the recall list.\n"; for(unit_map::iterator un = units_.begin(); un != units_.end(); ++un) { player_info *player=gamestate_.get_player(teams_[un->second.side()-1].save_id()); if(player) { + LOG_NG << "Added unit " << un->second.id() << ", " << un->second.name() << "\n"; un->second.new_turn(); un->second.new_level(); player->available_units.push_back(un->second); diff --git a/src/replay.cpp b/src/replay.cpp index df878a9e099..570f3fe7f08 100644 --- a/src/replay.cpp +++ b/src/replay.cpp @@ -167,6 +167,12 @@ void replay::set_save_info(const game_state& save) saveInfo_ = save; } +void replay::set_save_info(const game_state& save, const config::child_list& players) +{ + saveInfo_ = save; + saveInfo_.players.clear(); + saveInfo_.load_recall_list(players); +} void replay::set_save_info_completion(const std::string &st) // This function is a kluge to get around the fact that replay objects carry diff --git a/src/replay.hpp b/src/replay.hpp index 337839a4e21..1a9c627a8f7 100644 --- a/src/replay.hpp +++ b/src/replay.hpp @@ -43,6 +43,7 @@ public: explicit replay(const config& cfg); void set_save_info(const game_state& save); + void set_save_info(const game_state& save, const config::child_list& players); void set_save_info_completion(const std::string &st); void set_skip(bool skip);