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...
This commit is contained in:
Ignacio R. Morelle 2008-12-10 15:22:02 +00:00
parent 9eb5b01941
commit fb960ec58c
9 changed files with 53 additions and 9 deletions

View File

@ -58,6 +58,7 @@ Version 1.5.6+svn:
respectively, in [endlevel] or [campaign] tags. end_text_duration respectively, in [endlevel] or [campaign] tags. end_text_duration
is measured in milliseconds. (feature #10449) is measured in milliseconds. (feature #10449)
* Miscellaneous and bug fixes: * Miscellaneous and bug fixes:
* Fixed replays for single-player campaigns (bug #12005).
* New memory allocator introduced to the engine. It should * New memory allocator introduced to the engine. It should
produce 5-10% savings in memory usage on 64-bit systems. produce 5-10% savings in memory usage on 64-bit systems.
* Included extra headers for certain g++ versions (patch #1113). * Included extra headers for certain g++ versions (patch #1113).

View File

@ -35,6 +35,7 @@ Version 1.5.6+svn:
* Increased the cost of the Goblin Spearman from 8 to 9. * Increased the cost of the Goblin Spearman from 8 to 9.
* Miscellaneous and bugfixes * Miscellaneous and bugfixes
* Fixed single-player campaign scenario replays.
* Fixed random memory corruption/assertion failure/massive memory leak * Fixed random memory corruption/assertion failure/massive memory leak
due to story screens. due to story screens.

View File

@ -86,7 +86,7 @@ void get_player_info(const config& cfg, game_state& gamestate,
scenarios. Snapshots and replays are loaded from savegames and scenarios. Snapshots and replays are loaded from savegames and
got their own gold information, which must not be altered here got their own gold information, which must not be altered here
*/ */
if ( (player != NULL) && (!snapshot) && (!replay) ) { if ( (player != NULL) && (!snapshot) ) {
if(player->gold_add) { if(player->gold_add) {
ngold += player->gold; ngold += player->gold;
} else if(player->gold >= ngold) { } else if(player->gold >= ngold) {

View File

@ -530,6 +530,17 @@ game_state::game_state(const config& cfg, bool show_replay) :
const config* replay_start = cfg.child("replay_start"); const config* replay_start = cfg.child("replay_start");
if(replay_start != NULL) { if(replay_start != NULL) {
starting_pos = *replay_start; 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")) { if(cfg.child("statistics")) {
@ -569,6 +580,18 @@ static void write_player(const player_info& player, config& cfg)
cfg["can_recruit"] = can_recruit_str; cfg["can_recruit"] = can_recruit_str;
} }
void write_players(game_state& gamestate, config& cfg)
{
for(std::map<std::string, player_info>::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) static void write_player(config_writer &out, const player_info& player)
{ {
out.write_key_val("name", player.name); out.write_key_val("name", player.name);

View File

@ -103,6 +103,13 @@ public:
/** Return the Nth player, or NULL if no such player exists. */ /** Return the Nth player, or NULL if no such player exists. */
player_info* get_player(const std::string& id); 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_wml_variable*> scoped_variables; std::vector<scoped_wml_variable*> scoped_variables;
std::map<std::string, wml_menu_item*> wml_menu_items; std::map<std::string, wml_menu_item*> wml_menu_items;
@ -160,13 +167,6 @@ private:
mutable config temporaries; // lengths of arrays, etc. mutable config temporaries; // lengths of arrays, etc.
const rand_rng::set_random_generator generator_setter; /**< Make sure that rng is initialized first */ const rand_rng::set_random_generator generator_setter; /**< Make sure that rng is initialized first */
friend struct variable_info; 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 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(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); void write_game(config_writer &out, const game_state& gamestate, WRITE_GAME_MODE mode=WRITE_FULL_GAME);

View File

@ -416,6 +416,13 @@ LEVEL_RESULT play_game(display& disp, game_state& gamestate, const config& game_
gui::OK_CANCEL, _("Save Replay"), false, false) == 0) { gui::OK_CANCEL, _("Save Replay"), false, false) == 0) {
try { try {
config snapshot; 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); recorder.save_game(label, snapshot, gamestate.starting_pos);
} catch(game::save_game_failed&) { } catch(game::save_game_failed&) {
gui::show_error_message(disp, _("The replay could not be saved")); 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 // Sends scenario data
config cfg; config cfg;
cfg.add_child("store_next_scenario", *scenario); 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 // Adds player information, and other state
// information, to the configuration object // information, to the configuration object
assert(cfg.child("store_next_scenario") != NULL); assert(cfg.child("store_next_scenario") != NULL);

View File

@ -412,10 +412,12 @@ LEVEL_RESULT playsingle_controller::play_scenario(const std::vector<config*>& st
} }
// Add all the units that survived the scenario. // 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) { for(unit_map::iterator un = units_.begin(); un != units_.end(); ++un) {
player_info *player=gamestate_.get_player(teams_[un->second.side()-1].save_id()); player_info *player=gamestate_.get_player(teams_[un->second.side()-1].save_id());
if(player) { if(player) {
LOG_NG << "Added unit " << un->second.id() << ", " << un->second.name() << "\n";
un->second.new_turn(); un->second.new_turn();
un->second.new_level(); un->second.new_level();
player->available_units.push_back(un->second); player->available_units.push_back(un->second);

View File

@ -167,6 +167,12 @@ void replay::set_save_info(const game_state& save)
saveInfo_ = 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) void replay::set_save_info_completion(const std::string &st)
// This function is a kluge to get around the fact that replay objects carry // This function is a kluge to get around the fact that replay objects carry

View File

@ -43,6 +43,7 @@ public:
explicit replay(const config& cfg); explicit replay(const config& cfg);
void set_save_info(const game_state& save); 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_save_info_completion(const std::string &st);
void set_skip(bool skip); void set_skip(bool skip);