config_adapter.cpp

Go to the documentation of this file.
00001 /* $Id: config_adapter.cpp 25896 2008-04-17 19:05:35Z alink $ */
00002 /*
00003    Copyright (C) 2005 - 2008 by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
00004    wesnoth playlevel Copyright (C) 2003 by David White <dave@whitevine.net>
00005    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License version 2
00009    or at your option any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 //! @file config_adapter.cpp
00017 //! Construct objects like 'team' or 'unit' out of WML-based config-infos.
00018 
00019 #include "global.hpp"
00020 
00021 #include <sstream>
00022 #include "config_adapter.hpp"
00023 #include "game_errors.hpp"
00024 #include "game_preferences.hpp"
00025 #include "gamestatus.hpp"
00026 #include "gettext.hpp"
00027 #include "log.hpp"
00028 #include "team.hpp"
00029 #include "wml_exception.hpp"
00030 
00031 #define LOG_NG LOG_STREAM(info, engine)
00032 #define ERR_NG LOG_STREAM(err, engine)
00033 
00034 std::string get_unique_saveid(const config& cfg, std::set<std::string>& seen_save_ids)
00035 {
00036     std::string save_id = cfg["save_id"];
00037 
00038     if(save_id.empty()) {
00039         save_id=cfg["id"];
00040     }
00041 
00042     if(save_id.empty()) {
00043         save_id="Unknown";
00044     }
00045 
00046     // Make sure the 'save_id' is unique
00047     while(seen_save_ids.count(save_id)) {
00048         save_id += "_";
00049     }
00050 
00051     return save_id;
00052 }
00053 
00054 void get_player_info(const config& cfg, game_state& gamestate,
00055                      std::string save_id, std::vector<team>& teams,
00056                      const config& level, gamemap& map, unit_map& units,
00057                      gamestatus& game_status, bool snapshot, bool replay)
00058 {
00059     player_info *player = NULL;
00060 
00061     if(map.empty()) {
00062         throw game::load_game_failed("Map not found");
00063     }
00064 
00065     if(cfg["controller"] == "human" ||
00066        cfg["controller"] == "network" ||
00067        cfg["persistent"] == "1") {
00068         player = gamestate.get_player(save_id);
00069 
00070         if(player == NULL && !save_id.empty()) {
00071             player = &gamestate.players[save_id];
00072         }
00073     }
00074 
00075     LOG_NG << "initializing team...\n";
00076 
00077     std::string gold = cfg["gold"];
00078     if(gold.empty())
00079         gold = "100";
00080 
00081     LOG_NG << "found gold: '" << gold << "'\n";
00082 
00083     int ngold = lexical_cast_default<int>(gold);
00084 
00085     /* This is the gold carry-over mechanism for subsequent campaign
00086        scenarios. Snapshots and replays are loaded from savegames and
00087        got their own gold information, which must not be altered here
00088     */
00089     if ( (player != NULL)  && (!snapshot) && (!replay) ) {
00090         if(player->gold_add) {
00091             ngold +=  player->gold;
00092         } else if(player->gold >= ngold) {
00093             ngold = player->gold;
00094         }
00095     }
00096 
00097     LOG_NG << "set gold to '" << ngold << "'\n";
00098 
00099     team temp_team(cfg, ngold);
00100     teams.push_back(temp_team);
00101 
00102     // Update/fix the recall list for this side,
00103     // by setting the "side" of each unit in it
00104     // to be the "side" of the player.
00105     int side = lexical_cast_default<int>(cfg["side"], 1);
00106     if(player != NULL) {
00107         for(std::vector<unit>::iterator it = player->available_units.begin();
00108             it != player->available_units.end(); ++it) {
00109             it->set_side(side);
00110         }
00111     }
00112 
00113     // If this team has no objectives, set its objectives
00114     // to the level-global "objectives"
00115     if(teams.back().objectives().empty())
00116         teams.back().set_objectives(level["objectives"]);
00117 
00118     // If this side tag describes the leader of the side
00119     if(!utils::string_bool(cfg["no_leader"]) && cfg["controller"] != "null") {
00120         unit new_unit(&units, &map, &game_status, &teams, cfg, true);
00121 
00122         // Search the recall list for leader units, and if there is one,
00123         // use it in place of the config-described unit
00124         if(player != NULL) {
00125             for(std::vector<unit>::iterator it = player->available_units.begin();
00126                 it != player->available_units.end(); ++it) {
00127                 if(it->can_recruit()) {
00128                     new_unit = *it;
00129                     new_unit.set_game_context(&units, &map, &game_status, &teams);
00130                     player->available_units.erase(it);
00131                     break;
00132                 }
00133             }
00134         }
00135 
00136         // See if the side specifies its location.
00137         // Otherwise start it at the map-given starting position.
00138         gamemap::location start_pos(cfg, &gamestate);
00139 
00140         if(cfg["x"].empty() && cfg["y"].empty()) {
00141             start_pos = map.starting_position(side);
00142         }
00143 
00144         if(!start_pos.valid() || !map.on_board(start_pos)) {
00145             throw game::load_game_failed(
00146                 "Invalid starting position (" +
00147                 lexical_cast<std::string>(start_pos.x+1) +
00148                 "," + lexical_cast<std::string>(start_pos.y+1) +
00149                 ") for the leader of side " +
00150                 lexical_cast<std::string>(side) + ".");
00151         }
00152 
00153         utils::string_map symbols;
00154         symbols["side"] = lexical_cast<std::string>(side);
00155         VALIDATE(units.count(start_pos) == 0,
00156              t_string(vgettext("Duplicate side definition for side '$side|' found.", symbols)));
00157 
00158         units.add(new std::pair<gamemap::location,unit>(map.starting_position(new_unit.side()), new_unit));
00159         LOG_NG << "initializing side '" << cfg["side"] << "' at "
00160             << start_pos << '\n';
00161     }
00162 
00163     // If the game state specifies units that
00164     // can be recruited for the player, add them.
00165     if(player != NULL && player->can_recruit.empty() == false) {
00166         std::copy(player->can_recruit.begin(),player->can_recruit.end(),
00167                 std::inserter(teams.back().recruits(),teams.back().recruits().end()));
00168     }
00169 
00170     if(player != NULL) {
00171         player->can_recruit = teams.back().recruits();
00172     }
00173 
00174     // If there are additional starting units on this side
00175     const config::child_list& starting_units = cfg.get_children("unit");
00176     // available_units has been filled by loading the [player]-section already.
00177     // However, we need to get the information from the snapshot,
00178     // so we start from scratch here.
00179     // This is rather a quick hack, originating from keeping changes
00180     // as minimal as possible for 1.2.
00181     // Moving [player] into [replay_start] should be the correct way to go.
00182     if (player && snapshot){
00183         player->available_units.clear();
00184     }
00185     for(config::child_list::const_iterator su = starting_units.begin(); su != starting_units.end(); ++su) {
00186         unit new_unit(&units, &map, &game_status,&teams,**su,true);
00187 
00188         new_unit.set_side(side);
00189 
00190         const std::string& x = (**su)["x"];
00191         const std::string& y = (**su)["y"];
00192 
00193         gamemap::location loc(**su, &gamestate);
00194         if(x.empty() && y.empty()) {
00195             if(player) {
00196                 player->available_units.push_back(new_unit);
00197                 LOG_NG << "inserting unit on recall list for side " << new_unit.side() << "\n";
00198             } else {
00199                 throw game::load_game_failed(
00200                     "Attempt to create a unit on the recall list for side " +
00201                     lexical_cast<std::string>(side) +
00202                     ", which does not have a recall list.");
00203             }
00204         } else if(!loc.valid() || !map.on_board(loc)) {
00205             throw game::load_game_failed(
00206                 "Invalid starting position (" +
00207                 lexical_cast<std::string>(loc.x+1) +
00208                 "," + lexical_cast<std::string>(loc.y+1) +
00209                 ") for a unit on side " +
00210                 lexical_cast<std::string>(side) + ".");
00211         } else {
00212             if (units.find(loc) != units.end()) {
00213                 ERR_NG << "[unit] trying to overwrite existing unit at " << loc << "\n";
00214             } else {
00215                 units.add(new std::pair<gamemap::location,unit>(loc,new_unit));
00216                 LOG_NG << "inserting unit for side " << new_unit.side() << "\n";
00217             }
00218         }
00219     }
00220 }
00221 
00222 int get_first_human_team(const config::child_list::const_iterator& cfg, const config::child_list& unit_cfg){
00223     int result = -1;
00224     const std::string& controller = (**cfg)["controller"];
00225     if (controller == preferences::client_type() && (**cfg)["id"] == preferences::login()) {
00226         result = cfg - unit_cfg.begin();
00227     } else if((**cfg)["controller"] == "human") {
00228         result = cfg - unit_cfg.begin();
00229     }
00230     return result;
00231 }
00232 
00233 //! Return NULL if theme is not found.
00234 const config* get_theme(const config& game_config, std::string theme_name){
00235     const config* theme_cfg = NULL;
00236     if(theme_name != "") {
00237         theme_cfg = game_config.find_child("theme","name",theme_name);
00238     }
00239 
00240     if(theme_cfg == NULL) {
00241         theme_cfg = game_config.find_child("theme","name",preferences::theme());
00242     }
00243 
00244     return theme_cfg;
00245 }
00246 

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs