00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "global.hpp"
00020
00021 #include "playcampaign.hpp"
00022 #include "config.hpp"
00023 #include "filesystem.hpp"
00024 #include "game_preferences.hpp"
00025 #include "gamestatus.hpp"
00026 #include "map_create.hpp"
00027 #include "playmp_controller.hpp"
00028 #include "playsingle_controller.hpp"
00029 #include "replay.hpp"
00030 #include "replay_controller.hpp"
00031 #include "log.hpp"
00032 #include "dialogs.hpp"
00033 #include "gettext.hpp"
00034 #include "game_errors.hpp"
00035 #include "sound.hpp"
00036 #include "wml_exception.hpp"
00037
00038 #include <cassert>
00039 #include <map>
00040
00041 #define LOG_G LOG_STREAM(info, general)
00042 #define LOG_NG LOG_STREAM(info, engine)
00043
00044 namespace {
00045
00046 struct player_controller
00047 {
00048 player_controller() :
00049 controller(),
00050 description()
00051 {}
00052
00053 player_controller(const std::string& controller, const std::string& description) :
00054 controller(controller),
00055 description(description)
00056 {}
00057
00058 std::string controller;
00059 std::string description;
00060 };
00061
00062 typedef std::map<std::string, player_controller> controller_map;
00063
00064 }
00065
00066 void play_replay(display& disp, game_state& gamestate, const config& game_config,
00067 CVideo& video)
00068 {
00069 std::string type = gamestate.campaign_type;
00070 if(type.empty())
00071 type = "scenario";
00072
00073 config const* scenario = NULL;
00074
00075
00076 config starting_pos;
00077
00078 if (gamestate.starting_pos.empty()){
00079
00080 scenario = game_config.find_child(type,"id",gamestate.scenario);
00081 gamestate.starting_pos = *scenario;
00082 }
00083 recorder.set_save_info(gamestate);
00084 starting_pos = gamestate.starting_pos;
00085 scenario = &starting_pos;
00086
00087 try {
00088
00089 if (gamestate.label.empty())
00090 gamestate.label = (*scenario)["name"];
00091
00092
00093
00094 play_replay_level(game_config,scenario,video,gamestate);
00095
00096 gamestate.snapshot = config();
00097 recorder.clear();
00098 gamestate.replay_data.clear();
00099
00100 } catch(game::load_game_failed& e) {
00101 gui::show_error_message(disp, _("The game could not be loaded: ") + e.message);
00102 } catch(game::game_error& e) {
00103 gui::show_error_message(disp, _("Error while playing the game: ") + e.message);
00104 } catch(gamemap::incorrect_format_exception& e) {
00105 gui::show_error_message(disp, std::string(_("The game map could not be loaded: ")) + e.msg_);
00106 } catch(twml_exception& e) {
00107 e.show(disp);
00108 }
00109 }
00110
00111 static void clean_saves(const std::string &label)
00112 {
00113 std::vector<save_info> games = get_saves_list();
00114 std::string prefix = label + "-" + _("Auto-Save");
00115 std::cerr << "Cleaning saves with prefix '" << prefix << "'\n";
00116 for (std::vector<save_info>::iterator i = games.begin(); i != games.end(); i++) {
00117 if (i->name.compare(0, prefix.length(), prefix) == 0) {
00118 std::cerr << "Deleting savegame '" << i->name << "'\n";
00119 delete_game(i->name);
00120 }
00121 }
00122 }
00123
00124 static LEVEL_RESULT playsingle_scenario(const config& game_config,
00125 const config* level, display& disp, game_state& state_of_game,
00126 const std::vector<config*>& story, upload_log& log, bool skip_replay)
00127 {
00128 const int ticks = SDL_GetTicks();
00129 const int num_turns = atoi((*level)["turns"].c_str());
00130 LOG_NG << "creating objects... " << (SDL_GetTicks() - ticks) << "\n";
00131 playsingle_controller playcontroller(*level, state_of_game, ticks, num_turns, game_config, disp.video(), skip_replay);
00132 LOG_NG << "created objects... " << (SDL_GetTicks() - playcontroller.get_ticks()) << "\n";
00133
00134 const LEVEL_RESULT res = playcontroller.play_scenario(story, log, skip_replay);
00135
00136 if (res == DEFEAT) {
00137 gui::message_dialog(disp,
00138 _("Defeat"),
00139 _("You have been defeated!")
00140 ).show();
00141 }
00142
00143 if (!disp.video().faked() && res != QUIT && res != LEVEL_CONTINUE && res != LEVEL_CONTINUE_NO_SAVE)
00144 try {
00145 playcontroller.linger(log);
00146 } catch(end_level_exception& e) {
00147 if (e.result == QUIT) {
00148 return QUIT;
00149 }
00150 }
00151
00152 return res;
00153 }
00154
00155
00156 static LEVEL_RESULT playmp_scenario(const config& game_config,
00157 config const* level, display& disp, game_state& state_of_game,
00158 const config::child_list& story, upload_log& log, bool skip_replay,
00159 io_type_t& io_type)
00160 {
00161 const int ticks = SDL_GetTicks();
00162 const int num_turns = atoi((*level)["turns"].c_str());
00163 playmp_controller playcontroller(*level, state_of_game, ticks, num_turns,
00164 game_config, disp.video(), skip_replay, io_type == IO_SERVER);
00165 const LEVEL_RESULT res = playcontroller.play_scenario(story, log, skip_replay);
00166
00167
00168 if (io_type == IO_CLIENT && playcontroller.is_host())
00169 io_type = IO_SERVER;
00170
00171 if (res == DEFEAT) {
00172 gui::message_dialog(disp,
00173 _("Defeat"),
00174 _("You have been defeated!")
00175 ).show();
00176 }
00177
00178 if (!disp.video().faked() && res != QUIT) {
00179 if(res == LEVEL_CONTINUE || res == LEVEL_CONTINUE_NO_SAVE) {
00180 if(!playcontroller.is_host()) {
00181
00182
00183
00184 playcontroller.wait_for_upload();
00185 }
00186 } else {
00187 try {
00188 playcontroller.linger(log);
00189 } catch(end_level_exception& e) {
00190 if (e.result == QUIT) {
00191 return QUIT;
00192 }
00193 }
00194 }
00195 }
00196
00197 return res;
00198 }
00199
00200 LEVEL_RESULT play_game(display& disp, game_state& gamestate, const config& game_config,
00201 upload_log &log, io_type_t io_type, bool skip_replay)
00202 {
00203 std::string type = gamestate.campaign_type;
00204 if(type.empty())
00205 type = "scenario";
00206
00207 config const* scenario = NULL;
00208
00209
00210 config starting_pos;
00211
00212 recorder.set_save_info(gamestate);
00213
00214
00215
00216
00217 if(gamestate.snapshot.child("side") == NULL || !recorder.at_end()) {
00218 gamestate.completion = "running";
00219 recorder.set_save_info_completion(gamestate.completion);
00220
00221
00222
00223
00224 if(gamestate.starting_pos.empty() == false) {
00225 LOG_G << "loading starting position...\n";
00226 starting_pos = gamestate.starting_pos;
00227 scenario = &starting_pos;
00228 } else {
00229 LOG_G << "loading scenario: '" << gamestate.scenario << "'\n";
00230 scenario = game_config.find_child(type,"id",gamestate.scenario);
00231 if(scenario) {
00232 starting_pos = *scenario;
00233 gamestate.starting_pos = *scenario;
00234 }
00235 LOG_G << "scenario found: " << (scenario != NULL ? "yes" : "no") << "\n";
00236 }
00237 } else {
00238
00239 LOG_G << "loading snapshot...\n";
00240 starting_pos = gamestate.starting_pos;
00241 scenario = &gamestate.snapshot;
00242
00243
00244 if(gamestate.snapshot.child("variables") != NULL) {
00245 gamestate.set_variables(*gamestate.snapshot.child("variables"));
00246 }
00247 gamestate.set_menu_items(gamestate.snapshot.get_children("menu_item"));
00248
00249 if (!gamestate.snapshot["label"].empty()){
00250 gamestate.label = gamestate.snapshot["label"];
00251 }
00252 {
00253
00254
00255 const std::vector<config*>& player_cfg = gamestate.snapshot.get_children("player");
00256 for (std::vector<config*>::const_iterator p = player_cfg.begin(); p != player_cfg.end(); p++){
00257 std::string save_id = (**p)["save_id"];
00258 player_info* player = gamestate.get_player(save_id);
00259 if (player != NULL){
00260 player->gold = lexical_cast <int> ((**p)["gold"]);
00261 }
00262 }
00263 }
00264 {
00265
00266 const std::vector<config*>& player_cfg = gamestate.snapshot.get_children("side");
00267 for (std::vector<config*>::const_iterator p = player_cfg.begin(); p != player_cfg.end(); p++){
00268 std::string save_id = (**p)["save_id"];
00269 player_info* player = gamestate.get_player(save_id);
00270 if (player != NULL){
00271 const std::string& can_recruit_str = (**p)["recruit"];
00272 if(can_recruit_str != "") {
00273 player->can_recruit.clear();
00274 const std::vector<std::string> can_recruit = utils::split(can_recruit_str);
00275 std::copy(can_recruit.begin(),can_recruit.end(),std::inserter(player->can_recruit,player->can_recruit.end()));
00276 }
00277 }
00278 }
00279 }
00280 }
00281
00282 controller_map controllers;
00283
00284 if(io_type == IO_SERVER) {
00285 const config::child_list& sides_list = scenario->get_children("side");
00286 for(config::child_list::const_iterator side = sides_list.begin();
00287 side != sides_list.end(); ++side) {
00288 if ((**side)["current_player"] == preferences::login())
00289 {
00290 (**side)["controller"] = preferences::client_type();
00291 }
00292 std::string id = (**side)["save_id"];
00293 if(id.empty())
00294 continue;
00295 controllers[id] = player_controller((**side)["controller"],
00296 (**side)["id"]);
00297 }
00298 }
00299
00300 while(scenario != NULL) {
00301
00302 if(io_type == IO_CLIENT) {
00303 if(scenario != &starting_pos) {
00304 starting_pos = *scenario;
00305 scenario = &starting_pos;
00306 }
00307
00308 const config::child_list& sides_list = starting_pos.get_children("side");
00309 for(config::child_list::const_iterator side = sides_list.begin();
00310 side != sides_list.end(); ++side) {
00311 if((**side)["current_player"] == preferences::login()) {
00312 (**side)["controller"] = preferences::client_type();
00313 (**side)["persistent"] = "1";
00314 } else if((**side)["controller"] != "null") {
00315 (**side)["controller"] = "network";
00316 (**side)["persistent"] = "0";
00317 }
00318 }
00319 }
00320
00321 const config::child_list& story = scenario->get_children("story");
00322 gamestate.next_scenario = (*scenario)["next_scenario"];
00323
00324 bool save_game_after_scenario = true;
00325
00326 const set_random_generator generator_setter(&recorder);
00327 LEVEL_RESULT res = LEVEL_CONTINUE;
00328
00329 try {
00330
00331 if (gamestate.label.empty()) {
00332 if (gamestate.abbrev.empty())
00333 gamestate.label = (*scenario)["name"];
00334 else {
00335 gamestate.label = std::string(gamestate.abbrev);
00336 gamestate.label.append("-");
00337 gamestate.label.append((*scenario)["name"]);
00338 }
00339 }
00340
00341
00342 if((*scenario)["scenario_generation"] != "") {
00343 LOG_G << "randomly generating scenario...\n";
00344 const cursor::setter cursor_setter(cursor::WAIT);
00345
00346 static config scenario2;
00347 scenario2 = random_generate_scenario((*scenario)["scenario_generation"], scenario->child("generator"));
00348
00349
00350 gamestate.starting_pos = scenario2;
00351 scenario = &scenario2;
00352 }
00353 std::string map_data = (*scenario)["map_data"];
00354 if(map_data.empty() && (*scenario)["map"] != "") {
00355 map_data = read_map((*scenario)["map"]);
00356 }
00357
00358
00359 if(map_data.empty() && (*scenario)["map_generation"] != "") {
00360 const cursor::setter cursor_setter(cursor::WAIT);
00361 map_data = random_generate_map((*scenario)["map_generation"],scenario->child("generator"));
00362
00363
00364
00365
00366 static config new_level;
00367 new_level = *scenario;
00368 new_level.values["map_data"] = map_data;
00369 scenario = &new_level;
00370
00371 gamestate.starting_pos = new_level;
00372 LOG_G << "generated map\n";
00373 }
00374
00375 sound::play_no_music();
00376
00377 switch (io_type){
00378 case IO_NONE:
00379 res = playsingle_scenario(game_config,scenario,disp,gamestate,story,log, skip_replay);
00380 break;
00381 case IO_SERVER:
00382 case IO_CLIENT:
00383 res = playmp_scenario(game_config,scenario,disp,gamestate,story,log, skip_replay, io_type);
00384 break;
00385 }
00386 } catch(game::load_game_failed& e) {
00387 gui::show_error_message(disp, _("The game could not be loaded: ") + e.message);
00388 return QUIT;
00389 } catch(game::game_error& e) {
00390 gui::show_error_message(disp, _("Error while playing the game: ") + e.message);
00391 return QUIT;
00392 } catch(gamemap::incorrect_format_exception& e) {
00393 gui::show_error_message(disp, std::string(_("The game map could not be loaded: ")) + e.msg_);
00394 return QUIT;
00395 } catch(config::error& e) {
00396 std::cerr << "caught config::error...\n";
00397 gui::show_error_message(disp, _("Error while reading the WML: ") + e.message);
00398 return QUIT;
00399 } catch(twml_exception& e) {
00400 e.show(disp);
00401 return QUIT;
00402 }
00403
00404 gamestate.snapshot = config();
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416 if (res == VICTORY || (io_type != IO_NONE && (res == DEFEAT || res == OBSERVER_END))) {
00417 if (preferences::delete_saves())
00418 clean_saves(gamestate.label);
00419
00420 if (preferences::save_replays()) {
00421 std::string label = gamestate.label + _(" replay");
00422 if (dialogs::get_save_name(disp, "", _("Name: "), &label,
00423 gui::OK_CANCEL, _("Save Replay"), false, false) == 0) {
00424 try {
00425 config snapshot;
00426 recorder.save_game(label, snapshot, gamestate.starting_pos);
00427 } catch(game::save_game_failed&) {
00428 gui::show_error_message(disp, _("The replay could not be saved"));
00429 }
00430 }
00431 }
00432 }
00433
00434 recorder.clear();
00435 gamestate.replay_data.clear();
00436
00437
00438 if (res != VICTORY && res != LEVEL_CONTINUE_NO_SAVE
00439 && res != LEVEL_CONTINUE)
00440 {
00441 if (res != OBSERVER_END || gamestate.next_scenario.empty())
00442 return res;
00443
00444 const int dlg_res = gui::dialog(disp,"Game Over",
00445 _("This scenario has ended. Do you want to continue the campaign?"),
00446 gui::YES_NO).show();
00447 if (dlg_res != 0)
00448 return res;
00449 }
00450
00451
00452
00453 if(res == LEVEL_CONTINUE_NO_SAVE)
00454 save_game_after_scenario = false;
00455
00456
00457 gamestate.scenario = gamestate.next_scenario;
00458 gamestate.rng().rotate_random();
00459
00460 if(io_type == IO_CLIENT) {
00461 if (gamestate.next_scenario.empty()) return res;
00462
00463
00464 network::send_data(config("load_next_scenario"), 0, true);
00465 config cfg;
00466 std::string msg = _("Downloading next scenario...");
00467 do {
00468 cfg.clear();
00469 network::connection data_res = dialogs::network_receive_dialog(disp,
00470 msg, cfg);
00471 if(!data_res) return QUIT;
00472 } while(cfg.child("next_scenario") == NULL);
00473
00474 if(cfg.child("next_scenario")) {
00475 starting_pos = (*cfg.child("next_scenario"));
00476 scenario = &starting_pos;
00477 gamestate = game_state(starting_pos);
00478 } else {
00479 return QUIT;
00480 }
00481 } else {
00482 scenario = game_config.find_child(type,"id",gamestate.scenario);
00483
00484 if(io_type == IO_SERVER && scenario != NULL) {
00485 starting_pos = *scenario;
00486 scenario = &starting_pos;
00487
00488
00489 const config::child_list& sides_list = starting_pos.get_children("side");
00490 for(config::child_list::const_iterator side = sides_list.begin();
00491 side != sides_list.end(); ++side) {
00492 std::string id = (**side)["save_id"];
00493 if(id.empty()) {
00494 continue;
00495 }
00496
00497
00498
00499
00500
00501 controller_map::const_iterator ctr = controllers.find(id);
00502 if(ctr != controllers.end()) {
00503 player_info *player = gamestate.get_player(id);
00504 if (player) {
00505 (**side)["current_player"] = player->name;
00506
00507 (**side)["user_description"] = player->name;
00508 }
00509 (**side)["controller"] = ctr->second.controller;
00510 }
00511 }
00512
00513
00514 config cfg;
00515 cfg.add_child("store_next_scenario", *scenario);
00516
00517
00518
00519 assert(cfg.child("store_next_scenario") != NULL);
00520 write_game(gamestate, *cfg.child("store_next_scenario"), WRITE_SNAPSHOT_ONLY);
00521 network::send_data(cfg, 0, true);
00522 }
00523 }
00524
00525 if(scenario != NULL) {
00526
00527 std::string oldlabel = gamestate.label;
00528 if (gamestate.abbrev.empty())
00529 gamestate.label = (*scenario)["name"];
00530 else {
00531 gamestate.label = std::string(gamestate.abbrev);
00532 gamestate.label.append("-");
00533 gamestate.label.append((*scenario)["name"]);
00534 }
00535
00536
00537 if(save_game_after_scenario) {
00538
00539
00540
00541
00542
00543
00544
00545 if (gamestate.campaign_type == "multiplayer"){
00546 gamestate.starting_pos = *scenario;
00547 }
00548 else{
00549 gamestate.starting_pos = config();
00550 }
00551
00552 bool retry = true;
00553
00554 while(retry) {
00555 retry = false;
00556
00557 #ifdef TINY_GUI
00558 const int should_save = dialogs::get_save_name(disp,
00559 _("Do you want to save your game?"),
00560 _("Name:"),
00561 &gamestate.label);
00562 if(should_save == 0)
00563 #endif
00564 {
00565 try {
00566 save_game(gamestate);
00567 } catch(game::save_game_failed&) {
00568 gui::show_error_message(disp, _("The game could not be saved"));
00569 retry = true;
00570 }
00571 }
00572 }
00573 }
00574
00575 if (gamestate.campaign_type != "multiplayer"){
00576 gamestate.starting_pos = *scenario;
00577 }
00578 }
00579
00580 recorder.set_save_info(gamestate);
00581 }
00582
00583 if (!gamestate.scenario.empty() && gamestate.scenario != "null") {
00584 std::string message = _("Unknown scenario: '$scenario|'");
00585 utils::string_map symbols;
00586 symbols["scenario"] = gamestate.scenario;
00587 message = utils::interpolate_variables_into_string(message, &symbols);
00588 gui::show_error_message(disp, message);
00589 return QUIT;
00590 }
00591
00592 if (gamestate.campaign_type == "scenario"){
00593 if (preferences::delete_saves())
00594 clean_saves(gamestate.label);
00595 }
00596 return VICTORY;
00597 }
00598