editor/map/editor_map.cpp

Go to the documentation of this file.
00001 /* $Id: editor_map.cpp 53849 2012-04-08 07:37:23Z mordante $ */
00002 /*
00003    Copyright (C) 2008 - 2012 by Tomasz Sniatowski <kailoran@gmail.com>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (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 #define GETTEXT_DOMAIN "wesnoth-editor"
00016 
00017 #include "editor/action/action_base.hpp"
00018 #include "editor_map.hpp"
00019 #include "formula_string_utils.hpp"
00020 
00021 #include "display.hpp"
00022 #include "filesystem.hpp"
00023 #include "foreach.hpp"
00024 #include "gettext.hpp"
00025 #include "map_exception.hpp"
00026 #include "map_label.hpp"
00027 #include "wml_exception.hpp"
00028 
00029 
00030 namespace editor {
00031 
00032 editor_map_load_exception wrap_exc(const char* type, const std::string& e_msg, const std::string& filename)
00033 {
00034     WRN_ED << type << " error in load map " << filename << ": " << e_msg << "\n";
00035     utils::string_map symbols;
00036     symbols["type"] = type;
00037     const char* error_msg = "There was an error ($type) while loading the file:";
00038     std::string msg = vgettext(error_msg, symbols);
00039     msg += "\n";
00040     msg += e_msg;
00041     return editor_map_load_exception(filename, msg);
00042 }
00043 
00044 editor_map::editor_map(const config& terrain_cfg, const display& disp)
00045     : gamemap(terrain_cfg, "")
00046     , selection_()
00047     , labels_(disp, NULL)
00048     , units_()
00049     , teams_()
00050     , tod_manager_()
00051     , state_()
00052 {
00053 }
00054 
00055 editor_map::editor_map(const config& terrain_cfg, const config& level, const display& disp)
00056     : gamemap(terrain_cfg, level)
00057     , selection_()
00058     , labels_(disp, NULL)
00059     , units_()
00060     , teams_()
00061     , tod_manager_(level)
00062     , state_()
00063 {
00064     labels_.read(level);
00065 
00066     foreach (const config& side, level.child_range("side"))
00067     {
00068         team t;
00069         t.build(side, *this, 100);
00070         //this is done because we don't count as observer is there is a human controller
00071         t.change_controller("null");
00072         //TODO alternative? : gamestatus::teambuilder
00073 
00074         teams_.push_back(t);
00075         foreach (const config &a_unit, side.child_range("unit")) {
00076             map_location loc(a_unit, NULL);
00077             units_.add(loc, unit(a_unit, true));
00078         }
00079     }
00080 
00081     sanity_check();
00082 }
00083 
00084 editor_map::editor_map(const config& terrain_cfg, const std::string& data, const display& disp)
00085     : gamemap(terrain_cfg, data)
00086     , selection_()
00087     , labels_(disp, NULL)
00088     , units_()
00089     , teams_()
00090     , tod_manager_()
00091     , state_()
00092 {
00093     sanity_check();
00094 }
00095 
00096 editor_map editor_map::from_string(const config& terrain_cfg, const std::string& data, const display& disp)
00097 {
00098     try {
00099         return editor_map(terrain_cfg, data, disp);
00100     } catch (incorrect_map_format_error& e) {
00101         throw wrap_exc("format", e.message, "");
00102     } catch (twml_exception& e) {
00103         throw wrap_exc("wml", e.user_message, "");
00104     } catch (config::error& e) {
00105         throw wrap_exc("config", e.message, "");
00106     }
00107 }
00108 
00109 editor_map::editor_map(
00110           const config& terrain_cfg
00111         , size_t width
00112         , size_t height
00113         , t_translation::t_terrain filler
00114         , const display& disp)
00115     : gamemap(
00116               terrain_cfg
00117             , t_translation::write_game_map(t_translation::t_map(
00118                   width + 2
00119                 , t_translation::t_list(height + 2, filler))))
00120     , selection_()
00121     , labels_(disp, NULL)
00122     , units_()
00123     , teams_()
00124     , tod_manager_()
00125     , state_()
00126 {
00127     sanity_check();
00128 }
00129 
00130 editor_map::editor_map(const gamemap& map, const display& disp)
00131     : gamemap(map)
00132     , selection_()
00133     , labels_(disp, NULL)
00134     , units_()
00135     , teams_()
00136     , tod_manager_()
00137     , state_()
00138 {
00139     sanity_check();
00140 }
00141 
00142 editor_map::~editor_map()
00143 {
00144 }
00145 
00146 void editor_map::sanity_check()
00147 {
00148     int errors = 0;
00149     if (total_width() != static_cast<int>(tiles_.size())) {
00150         ERR_ED << "total_width is " << total_width() << " but tiles_.size() is " << tiles_.size() << "\n";
00151         ++errors;
00152     }
00153     if (total_height() != static_cast<int>(tiles_[0].size())) {
00154         ERR_ED << "total_height is " << total_height() << " but tiles_[0].size() is " << tiles_.size() << "\n";
00155         ++errors;
00156     }
00157     if (w() + 2 * border_size() != total_width()) {
00158         ERR_ED << "h is " << h_ << " and border_size is " << border_size() << " but total_width is " << total_width() << "\n";
00159         ++errors;
00160     }
00161     if (h() + 2 * border_size() != total_height()) {
00162         ERR_ED << "w is " << w_ << " and border_size is " << border_size() << " but total_height is " << total_height() << "\n";
00163         ++errors;
00164     }
00165     for (size_t i = 1; i < tiles_.size(); ++i) {
00166         if (tiles_[i].size() != tiles_[0].size()) {
00167             ERR_ED << "tiles_[ " << i << "] has size() " << tiles_[i].size() << " but tiles[0] has size() " << tiles_[0].size() << "\n";
00168             ++errors;
00169         }
00170     }
00171     foreach (const map_location& loc, selection_) {
00172         if (!on_board_with_border(loc)) {
00173             ERR_ED << "Off-map tile in selection: " << loc << "\n";
00174         }
00175     }
00176     if (errors) {
00177         throw editor_map_integrity_error();
00178     }
00179 }
00180 
00181 std::set<map_location> editor_map::get_contiguous_terrain_tiles(const map_location& start) const
00182 {
00183     t_translation::t_terrain terrain = get_terrain(start);
00184     std::set<map_location> result;
00185     std::deque<map_location> queue;
00186     result.insert(start);
00187     queue.push_back(start);
00188     //this is basically a breadth-first search along adjacent hexes
00189     do {
00190         map_location adj[6];
00191         get_adjacent_tiles(queue.front(), adj);
00192         for (int i = 0; i < 6; ++i) {
00193             if (on_board_with_border(adj[i]) && get_terrain(adj[i]) == terrain
00194             && result.find(adj[i]) == result.end()) {
00195                 result.insert(adj[i]);
00196                 queue.push_back(adj[i]);
00197             }
00198         }
00199         queue.pop_front();
00200     } while (!queue.empty());
00201     return result;
00202 }
00203 
00204 std::set<map_location> editor_map::set_starting_position_labels(display& disp)
00205 {
00206     std::set<map_location> label_locs;
00207     std::string label = _("Player");
00208     label += " ";
00209     for (int i = 1; i <= gamemap::MAX_PLAYERS; i++) {
00210         if (startingPositions_[i].valid()) {
00211             disp.labels().set_label(startingPositions_[i], label + lexical_cast<std::string>(i));
00212             label_locs.insert(startingPositions_[i]);
00213         }
00214     }
00215     return label_locs;
00216 }
00217 
00218 bool editor_map::in_selection(const map_location& loc) const
00219 {
00220     return selection_.find(loc) != selection_.end();
00221 }
00222 
00223 bool editor_map::add_to_selection(const map_location& loc)
00224 {
00225     return on_board_with_border(loc) ? selection_.insert(loc).second : false;
00226 }
00227 
00228 bool editor_map::remove_from_selection(const map_location& loc)
00229 {
00230     return selection_.erase(loc) != 0;
00231 }
00232 
00233 void editor_map::clear_selection()
00234 {
00235     selection_.clear();
00236 }
00237 
00238 void editor_map::invert_selection()
00239 {
00240     std::set<map_location> new_selection;
00241     for (int x = -1; x < w() + 1; ++x) {
00242         for (int y = -1; y < h() + 1; ++y) {
00243             if (selection_.find(map_location(x, y)) == selection_.end()) {
00244                 new_selection.insert(map_location(x, y));
00245             }
00246         }
00247     }
00248     selection_.swap(new_selection);
00249 }
00250 
00251 void editor_map::select_all()
00252 {
00253     clear_selection();
00254     invert_selection();
00255 }
00256 
00257 bool editor_map::everything_selected() const
00258 {
00259     LOG_ED << selection_.size() << " " << total_width() * total_height() << "\n";
00260     return static_cast<int>(selection_.size()) == total_width() * total_height();
00261 }
00262 
00263 void editor_map::resize(int width, int height, int x_offset, int y_offset,
00264     t_translation::t_terrain filler)
00265 {
00266     int old_w = w();
00267     int old_h = h();
00268     if (old_w == width && old_h == height && x_offset == 0 && y_offset == 0) {
00269         return;
00270     }
00271 
00272     // Determine the amount of resizing is required
00273     const int left_resize = -x_offset;
00274     const int right_resize = (width - old_w) + x_offset;
00275     const int top_resize = -y_offset;
00276     const int bottom_resize = (height - old_h) + y_offset;
00277 
00278     if(right_resize > 0) {
00279         expand_right(right_resize, filler);
00280     } else if(right_resize < 0) {
00281         shrink_right(-right_resize);
00282     }
00283     if(bottom_resize > 0) {
00284         expand_bottom(bottom_resize, filler);
00285     } else if(bottom_resize < 0) {
00286         shrink_bottom(-bottom_resize);
00287     }
00288     if(left_resize > 0) {
00289         expand_left(left_resize, filler);
00290     } else if(left_resize < 0) {
00291         shrink_left(-left_resize);
00292     }
00293     if(top_resize > 0) {
00294         expand_top(top_resize, filler);
00295     } else if(top_resize < 0) {
00296         shrink_top(-top_resize);
00297     }
00298 
00299     // fix the starting positions
00300     if(x_offset || y_offset) {
00301         for(size_t i = 0; i < MAX_PLAYERS+1; ++i) {
00302             if(startingPositions_[i] != map_location()) {
00303                 startingPositions_[i].x -= x_offset;
00304                 startingPositions_[i].y -= y_offset;
00305             }
00306         }
00307     }
00308     sanity_check();
00309 }
00310 
00311 editor_map editor_map::mask_to(const editor_map& target) const
00312 {
00313     if (target.w() != w() || target.h() != h()) {
00314         throw editor_action_exception(_("The size of the target map is different from the current map"));
00315     }
00316     editor_map mask(target);
00317     map_location iter;
00318     for (iter.x = -border_size(); iter.x < w() + border_size(); ++iter.x) {
00319         for (iter.y = -border_size(); iter.y < h() + border_size(); ++iter.y) {
00320             if (target.get_terrain(iter) == get_terrain(iter)) {
00321                 mask.set_terrain(iter, t_translation::FOGGED);
00322             }
00323         }
00324     }
00325     return mask;
00326 }
00327 
00328 bool editor_map::same_size_as(const gamemap& other) const
00329 {
00330     return h() == other.h()
00331         && w() == other.w();
00332 }
00333 
00334 t_translation::t_list editor_map::clone_column(int x, t_translation::t_terrain filler)
00335 {
00336     int h = tiles_[1].size();
00337     t_translation::t_list column(h);
00338     for (int y = 0; y < h; ++y) {
00339         column[y] =
00340             filler != t_translation::NONE_TERRAIN ?
00341             filler :
00342             tiles_[x][y];
00343         assert(column[y] != t_translation::NONE_TERRAIN);
00344     }
00345     return column;
00346 }
00347 
00348 void editor_map::expand_right(int count, t_translation::t_terrain filler)
00349 {
00350     int w = tiles_.size();
00351     for (int x = 0; x < count; ++x) {
00352         tiles_.push_back(clone_column(w - 1 , filler));
00353     }
00354     w_ += count;
00355     total_width_ += count;
00356 }
00357 
00358 void editor_map::expand_left(int count, t_translation::t_terrain filler)
00359 {
00360     for (int x = 0; x < count; ++x) {
00361         tiles_.insert(tiles_.begin(), 1, clone_column(0, filler));
00362         clear_border_cache();
00363     }
00364     w_ += count;
00365     total_width_ += count;
00366 }
00367 
00368 void editor_map::expand_top(int count, t_translation::t_terrain filler)
00369 {
00370     for (int y = 0; y < count; ++y) {
00371         for (int x = 0; x < static_cast<int>(tiles_.size()); ++x) {
00372             t_translation::t_terrain terrain =
00373                 filler != t_translation::NONE_TERRAIN ?
00374                 filler :
00375                 tiles_[x][0];
00376             assert(terrain != t_translation::NONE_TERRAIN);
00377             tiles_[x].insert(tiles_[x].begin(), 1, terrain);
00378             clear_border_cache();
00379         }
00380     }
00381     h_ += count;
00382     total_height_ += count;
00383 }
00384 
00385 void editor_map::expand_bottom(int count, t_translation::t_terrain filler)
00386 {
00387     int h = tiles_[1].size();
00388     for (int y = 0; y < count; ++y) {
00389         for (int x = 0; x < static_cast<int>(tiles_.size()); ++x) {
00390             t_translation::t_terrain terrain =
00391                 filler != t_translation::NONE_TERRAIN ?
00392                 filler :
00393                 tiles_[x][h - 1];
00394             assert(terrain != t_translation::NONE_TERRAIN);
00395             tiles_[x].push_back(terrain);
00396         }
00397     }
00398     h_ += count;
00399     total_height_ += count;
00400 }
00401 
00402 void editor_map::shrink_right(int count)
00403 {
00404     if(count < 0 || count > static_cast<int>(tiles_.size())) {
00405         throw editor_map_operation_exception();
00406     }
00407     tiles_.resize(tiles_.size() - count);
00408     w_ -= count;
00409     total_width_ -= count;
00410 }
00411 
00412 void editor_map::shrink_left(int count)
00413 {
00414     if(count < 0 || count > static_cast<int>(tiles_.size())) {
00415         throw editor_map_operation_exception();
00416     }
00417     tiles_.erase(tiles_.begin(), tiles_.begin() + count);
00418     w_ -= count;
00419     total_width_ -= count;
00420 }
00421 
00422 void editor_map::shrink_top(int count)
00423 {
00424     if(count < 0 || count > static_cast<int>(tiles_[0].size())) {
00425         throw editor_map_operation_exception();
00426     }
00427     for (size_t x = 0; x < tiles_.size(); ++x) {
00428         tiles_[x].erase(tiles_[x].begin(), tiles_[x].begin() + count);
00429     }
00430     h_ -= count;
00431     total_height_ -= count;
00432 }
00433 
00434 void editor_map::shrink_bottom(int count)
00435 {
00436     if(count < 0 || count > static_cast<int>(tiles_[0].size())) {
00437         throw editor_map_operation_exception();
00438     }
00439     for (size_t x = 0; x < tiles_.size(); ++x) {
00440         tiles_[x].erase(tiles_[x].end() - count, tiles_[x].end());
00441     }
00442     h_ -= count;
00443     total_height_ -= count;
00444 }
00445 
00446 void editor_map::write(config& cfg) const {
00447     config& map = cfg.add_child("map");
00448     gamemap::write(map);
00449     labels_.write(cfg);
00450 }
00451 
00452 } //end namespace editor
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:35 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs