00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "map_manip.hpp"
00019
00020 #include "../gettext.hpp"
00021 #include "../map.hpp"
00022 #include "../config.hpp"
00023 #include "../construct_dialog.hpp"
00024 #include "../util.hpp"
00025 #include "../wml_exception.hpp"
00026 #include "serialization/string_utils.hpp"
00027
00028 #include <algorithm>
00029 #include <cassert>
00030 #include <map>
00031 #include <set>
00032 #include <sstream>
00033 #include <vector>
00034
00035 std::string editormap::resize(const size_t width, const size_t height,
00036 const int x_offset, const int y_offset,
00037 const bool do_expand, t_translation::t_terrain filler)
00038 {
00039
00040 const unsigned old_w = static_cast<unsigned>(w());
00041 const unsigned old_h = static_cast<unsigned>(h());
00042
00043
00044 if(old_w == width && old_h == height && x_offset == 0 && y_offset == 0 ) {
00045 return "";
00046 }
00047
00048 if(do_expand) {
00049 filler = t_translation::NONE_TERRAIN;
00050 }
00051
00052
00053 const int left_resize = -x_offset;
00054 const int right_resize = (width - old_w) + x_offset;
00055 const int top_resize = -y_offset;
00056 const int bottom_resize = (height - old_h) + y_offset;
00057
00058
00059
00060
00061 if(right_resize > 0) {
00062 add_tiles_right(right_resize, filler);
00063 } else if(right_resize < 0) {
00064 remove_tiles_right(-right_resize);
00065 }
00066
00067 if(bottom_resize > 0) {
00068 add_tiles_bottom(bottom_resize, filler);
00069 } else if(bottom_resize < 0) {
00070 remove_tiles_bottom(-bottom_resize);
00071 }
00072
00073 if(left_resize > 0) {
00074 add_tiles_left(left_resize, filler);
00075 } else if(left_resize < 0) {
00076 remove_tiles_left(-left_resize);
00077 }
00078
00079 if(top_resize > 0) {
00080 add_tiles_top(top_resize, filler);
00081 } else if(top_resize < 0) {
00082 remove_tiles_top(-top_resize);
00083 }
00084
00085
00086 if(x_offset || y_offset) {
00087 for(size_t i = 0; i < MAX_PLAYERS+1; ++i) {
00088 if(startingPositions_[i] != gamemap::location()) {
00089 startingPositions_[i].x -= x_offset;
00090 startingPositions_[i].y -= y_offset;
00091 }
00092 }
00093 }
00094
00095
00096 return write();
00097 }
00098
00099 std::string editormap::flip(const map_editor::FLIP_AXIS axis)
00100 {
00101 if(axis != map_editor::FLIP_X && axis != map_editor::FLIP_Y) {
00102 return "";
00103 }
00104
00105 if(axis == map_editor::FLIP_X) {
00106
00107
00108
00109
00110 const size_t middle = (tiles_[0].size() / 2);
00111 const size_t end = tiles_[0].size() - 1;
00112 for(size_t x = 0; x < tiles_.size(); ++x) {
00113 if(x % 2) {
00114
00115 tiles_[x].resize(tiles_[x].size() + 1, tiles_[x][0]);
00116
00117 for(size_t y1 = 0, y2 = end; y1 < middle; ++y1, --y2) {
00118 swap_starting_position(x, y1, x, y2);
00119 std::swap(tiles_[x][y1], tiles_[x][y2]);
00120 }
00121 } else {
00122
00123 tiles_[x].resize(tiles_[x].size() + 1, tiles_[x][end]);
00124
00125 for(size_t y1 = 0, y2 = end + 1; y1 < middle; ++y1, --y2) {
00126 swap_starting_position(x, y1, x, y2);
00127 std::swap(tiles_[x][y1], tiles_[x][y2]);
00128 }
00129
00130 }
00131 }
00132 } else {
00133
00134
00135 const size_t middle = (tiles_.size() / 2);
00136 const size_t end = tiles_.size() - 1;
00137 for(size_t y = 0; y < tiles_[0].size(); ++y) {
00138 for(size_t x1 = 0, x2 = end; x1 < middle; ++x1, --x2) {
00139 swap_starting_position(x1, y, x2, y);
00140 std::swap(tiles_[x1][y], tiles_[x2][y]);
00141 }
00142 }
00143 }
00144
00145 return write();
00146 }
00147
00148 void editormap::set_starting_position(const int pos, const location loc) {
00149 startingPositions_[pos] = loc;
00150 }
00151
00152 void editormap::swap_starting_position(const size_t x1, const size_t y1,
00153 const size_t x2, const size_t y2)
00154 {
00155 const int pos1 = is_starting_position(location(x1, y1));
00156 const int pos2 = is_starting_position(location(x2, y2));
00157
00158 if(pos1 != -1) {
00159 set_starting_position(pos1 + 1, location(x2, y2));
00160 }
00161
00162 if(pos2 != -1) {
00163 set_starting_position(pos2 + 1, location(x1, y1));
00164 }
00165 }
00166
00167 void editormap::add_tiles_right(
00168 const unsigned count, const t_translation::t_terrain& filler)
00169 {
00170 for(size_t x = 1; x <= count; ++x) {
00171 t_translation::t_list one_row(tiles_[1].size());
00172 for(size_t y = 0; y < tiles_[1].size(); ++y) {
00173 one_row[y] =
00174 filler != t_translation::NONE_TERRAIN ?
00175 filler :
00176 tiles_[x - 1][y];
00177
00178 assert(one_row[y] != t_translation::NONE_TERRAIN);
00179 }
00180 tiles_.push_back(one_row);
00181 }
00182 }
00183
00184 void editormap::add_tiles_left(
00185 const unsigned count, const t_translation::t_terrain& filler)
00186 {
00187 for(size_t i = 1; i <= count; ++i) {
00188 t_translation::t_list one_row(tiles_[1].size());
00189 for(size_t y = 0; y < tiles_[1].size(); ++y) {
00190 one_row[y] =
00191 filler != t_translation::NONE_TERRAIN ?
00192 filler :
00193 tiles_[0][y];
00194
00195 assert(one_row[y] != t_translation::NONE_TERRAIN);
00196 }
00197 tiles_.insert(tiles_.begin(), 1, one_row);
00198 clear_border_cache();
00199 }
00200 }
00201
00202 void editormap::remove_tiles_right(const unsigned count)
00203 {
00204 if(count > tiles_.size()) {
00205 std::stringstream sstr;
00206 sstr << _("Can't resize the map, the requested size is bigger "
00207 "than the maximum, size=") << count << _(" maximum=")
00208 << tiles_.size();
00209
00210 throw incorrect_format_exception(sstr.str().c_str());
00211 }
00212
00213 tiles_.resize(tiles_.size() - count);
00214 }
00215
00216 void editormap::remove_tiles_left(const unsigned count)
00217 {
00218 if(count > tiles_.size()) {
00219 std::stringstream sstr;
00220 sstr << _("Can't resize the map, the requested size is bigger "
00221 "than the maximum, size=") << count << _(" maximum=")
00222 << tiles_.size();
00223
00224 throw incorrect_format_exception(sstr.str().c_str());
00225 }
00226
00227 tiles_.erase(tiles_.begin(), tiles_.begin() + count);
00228 }
00229
00230 void editormap::add_tiles_top(
00231 const unsigned count, const t_translation::t_terrain& filler)
00232 {
00233 for(size_t i = 1; i <= count; ++i) {
00234 for(size_t y = 0; y < tiles_.size(); ++y) {
00235 t_translation::t_terrain terrain =
00236 filler != t_translation::NONE_TERRAIN ?
00237 filler :
00238 tiles_[y][0];
00239
00240 assert(terrain != t_translation::NONE_TERRAIN);
00241 tiles_[y].insert(tiles_[y].begin(), 1, terrain);
00242 clear_border_cache();
00243 }
00244 }
00245 }
00246
00247 void editormap::add_tiles_bottom(
00248 const unsigned count, const t_translation::t_terrain& filler)
00249 {
00250 for(size_t i = 1; i <= count; ++i) {
00251 for(size_t x = 0; x < tiles_.size(); ++x) {
00252 t_translation::t_terrain terrain =
00253 filler != t_translation::NONE_TERRAIN ?
00254 filler :
00255 tiles_[x][i - 1];
00256
00257 assert(terrain != t_translation::NONE_TERRAIN);
00258 tiles_[x].push_back(terrain);
00259 }
00260 }
00261 }
00262
00263 void editormap::remove_tiles_top(const unsigned count)
00264 {
00265 if(count > tiles_[0].size()) {
00266 std::stringstream sstr;
00267 sstr << _("Can't resize the map, the requested size is bigger "
00268 "than the maximum, size=") << count << _(" maximum=")
00269 << tiles_[0].size();
00270
00271 throw incorrect_format_exception(sstr.str().c_str());
00272 }
00273
00274 for(size_t x = 0; x < tiles_.size(); ++x) {
00275 tiles_[x].erase(tiles_[x].begin(), tiles_[x].begin() + count);
00276 }
00277 }
00278
00279 void editormap::remove_tiles_bottom(const unsigned count)
00280 {
00281 if(count > tiles_[0].size()) {
00282 std::stringstream sstr;
00283 sstr << _("Can't resize the map, the requested size is bigger "
00284 "than the maximum, size=") << count << _(" maximum=")
00285 << tiles_[0].size();
00286
00287 throw incorrect_format_exception(sstr.str().c_str());
00288 }
00289
00290 for(size_t x = 0; x < tiles_.size(); ++x) {
00291 tiles_[x].erase(tiles_[x].end() - count, tiles_[x].end());
00292 }
00293
00294 }
00295
00296 namespace map_editor {
00297
00298 std::vector<gamemap::location> get_tiles(const gamemap &map,
00299 const gamemap::location& a,
00300 const unsigned int radius) {
00301 const unsigned int distance = radius - 1;
00302 std::vector<gamemap::location> res;
00303 res.push_back(a);
00304 for (unsigned int d = 1; d <= distance; d++) {
00305 gamemap::location loc = a;
00306 unsigned int i;
00307
00308 for (i = 1; i <= d; i++) {
00309 loc = loc.get_direction(gamemap::location::NORTH, 1);
00310 }
00311
00312 const gamemap::location::DIRECTION direction[6] =
00313 {gamemap::location::SOUTH_EAST, gamemap::location::SOUTH, gamemap::location::SOUTH_WEST,
00314 gamemap::location::NORTH_WEST, gamemap::location::NORTH, gamemap::location::NORTH_EAST};
00315 for (i = 0; i < 6; i++) {
00316 for (unsigned int j = 1; j <= d; j++) {
00317 loc = loc.get_direction(direction[i], 1);
00318 if (map.on_board(loc, true)) {
00319 res.push_back(loc);
00320 }
00321 }
00322 }
00323 }
00324 return res;
00325 }
00326
00327 void flood_fill(gamemap &map, const gamemap::location &start_loc,
00328 const t_translation::t_terrain fill_with, terrain_log *log)
00329 {
00330 t_translation::t_terrain terrain_to_fill = map.get_terrain(start_loc);
00331 if (fill_with == terrain_to_fill) {
00332 return;
00333 }
00334 std::set<gamemap::location> to_fill = get_component(map, start_loc);
00335 std::set<gamemap::location>::iterator it;
00336 for (it = to_fill.begin(); it != to_fill.end(); it++) {
00337 gamemap::location loc = *it;
00338 if (log != NULL) {
00339 log->push_back(std::make_pair(loc, terrain_to_fill));
00340 }
00341 if (fill_with.base == t_translation::NO_LAYER) {
00342 map.set_terrain(loc, fill_with, gamemap::OVERLAY);
00343 }
00344 else {
00345 map.set_terrain(loc, fill_with);
00346 }
00347 }
00348 }
00349
00350 std::set<gamemap::location> get_component(const gamemap &map,
00351 const gamemap::location &start_loc)
00352 {
00353 t_translation::t_terrain terrain_to_fill = map.get_terrain(start_loc);
00354 std::set<gamemap::location> to_fill;
00355 std::set<gamemap::location> filled;
00356 std::set<gamemap::location>::iterator it;
00357
00358
00359
00360
00361 to_fill.insert(start_loc);
00362 while (!to_fill.empty()) {
00363 it = to_fill.begin();
00364 gamemap::location loc = *it;
00365 to_fill.erase(it);
00366 filled.insert(loc);
00367
00368
00369 std::vector<gamemap::location> adj = get_tiles(map, loc, 2);
00370 for (std::vector<gamemap::location>::iterator it2 = adj.begin();
00371 it2 != adj.end(); it2++) {
00372 if (map.on_board(*it2, true) && map.get_terrain(*it2) == terrain_to_fill
00373 && filled.find(*it2) == filled.end()) {
00374 to_fill.insert(*it2);
00375 }
00376 }
00377 }
00378 return filled;
00379 }
00380
00381 std::string resize_map(editormap &map, const unsigned new_w,
00382 const unsigned new_h, const int off_x, const int off_y,
00383 const bool do_expand, const t_translation::t_terrain fill_with)
00384 {
00385 return map.resize(new_w, new_h, off_x, off_y, do_expand, fill_with);
00386 }
00387
00388
00389 std::string flip_map(editormap &map, const FLIP_AXIS axis) {
00390 return map.flip(axis);
00391 }
00392
00393 bool valid_mapdata(const std::string &data, const config &cfg) {
00394 bool res = data.size() != 0;
00395
00396
00397 try {
00398 const gamemap m(cfg, data);
00399
00400
00401 res = m.w() != 0 && m.h() != 0;
00402 }
00403 catch (gamemap::incorrect_format_exception) {
00404 res = false;
00405 } catch(twml_exception& e) {
00406 std::cerr << "WML exception:\nUser message: "
00407 << e.user_message << "\nDev message: " << e.dev_message << '\n';
00408 return false;
00409 }
00410 return res;
00411 }
00412
00413 std::string new_map(const size_t width, const size_t height, const t_translation::t_terrain filler)
00414 {
00415 const t_translation::t_list column(height, filler);
00416 const t_translation::t_map map(width, column);
00417
00418 return gamemap::default_map_header + t_translation::write_game_map(map);
00419
00420 }
00421
00422 }
00423