The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
editor_map.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2017 by Tomasz Sniatowski <kailoran@gmail.com>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 #define GETTEXT_DOMAIN "wesnoth-editor"
15 
18 #include "formula/string_utils.hpp"
19 
20 #include "display.hpp"
21 #include "formula/string_utils.hpp"
22 #include "gettext.hpp"
23 #include "map/exception.hpp"
24 #include "map/label.hpp"
25 #include "wml_exception.hpp"
26 
27 #include "terrain/type_data.hpp"
28 
29 namespace editor {
30 
31 editor_map_load_exception wrap_exc(const char* type, const std::string& e_msg, const std::string& filename)
32 {
33  WRN_ED << type << " error in load map " << filename << ": " << e_msg << std::endl;
34  utils::string_map symbols;
35  symbols["type"] = type;
36  const char* error_msg = "There was an error ($type) while loading the file:";
37  std::string msg = vgettext(error_msg, symbols);
38  msg += "\n";
39  msg += e_msg;
40  return editor_map_load_exception(filename, msg);
41 }
42 
43 editor_map::editor_map(const config& terrain_cfg)
44  : gamemap(std::make_shared<terrain_type_data>(terrain_cfg), "")
45  , selection_()
46 {
47 }
48 
49 editor_map::editor_map(const config& terrain_cfg, const std::string& data)
50  : gamemap(std::make_shared<terrain_type_data>(terrain_cfg), data)
51  , selection_()
52 {
53  sanity_check();
54 }
55 
56 editor_map editor_map::from_string(const config& terrain_cfg, const std::string& data)
57 {
58  try {
59  return editor_map(terrain_cfg, data);
60  } catch (incorrect_map_format_error& e) {
61  throw wrap_exc("format", e.message, "");
62  } catch (wml_exception& e) {
63  throw wrap_exc("wml", e.user_message, "");
64  } catch (config::error& e) {
65  throw wrap_exc("config", e.message, "");
66  }
67 }
68 
69 editor_map::editor_map(const config& terrain_cfg, size_t width, size_t height, const t_translation::terrain_code & filler)
70  : gamemap(std::make_shared<terrain_type_data>(terrain_cfg), t_translation::write_game_map(t_translation::ter_map(width + 2, height + 2, filler)))
71  , selection_()
72 {
73  sanity_check();
74 }
75 
77  : gamemap(map)
78  , selection_()
79 {
80  sanity_check();
81 }
82 
84 {
85 }
86 
88 {
89  int errors = 0;
90  if (total_width() != tiles_.w) {
91  ERR_ED << "total_width is " << total_width() << " but tiles_.size() is " << tiles_.w << std::endl;
92  ++errors;
93  }
94  if (total_height() != tiles_.h) {
95  ERR_ED << "total_height is " << total_height() << " but tiles_[0].size() is " << tiles_.h << std::endl;
96  ++errors;
97  }
98  if (w() + 2 * border_size() != total_width()) {
99  ERR_ED << "h is " << h_ << " and border_size is " << border_size() << " but total_width is " << total_width() << std::endl;
100  ++errors;
101  }
102  if (h() + 2 * border_size() != total_height()) {
103  ERR_ED << "w is " << w_ << " and border_size is " << border_size() << " but total_height is " << total_height() << std::endl;
104  ++errors;
105  }
106  for (const map_location& loc : selection_) {
107  if (!on_board_with_border(loc)) {
108  ERR_ED << "Off-map tile in selection: " << loc << std::endl;
109  }
110  }
111  if (errors) {
113  }
114 }
115 
116 std::set<map_location> editor_map::get_contiguous_terrain_tiles(const map_location& start) const
117 {
119  std::set<map_location> result;
120  std::deque<map_location> queue;
121  result.insert(start);
122  queue.push_back(start);
123  //this is basically a breadth-first search along adjacent hexes
124  do {
125  map_location adj[6];
126  get_adjacent_tiles(queue.front(), adj);
127  for (int i = 0; i < 6; ++i) {
128  if (on_board_with_border(adj[i]) && get_terrain(adj[i]) == terrain
129  && result.find(adj[i]) == result.end()) {
130  result.insert(adj[i]);
131  queue.push_back(adj[i]);
132  }
133  }
134  queue.pop_front();
135  } while (!queue.empty());
136  return result;
137 }
138 
140 {
141  std::set<map_location> label_locs;
142  std::string label;
143 
144 
145  for (const auto& pair : starting_positions_.left) {
146 
147  bool is_number = std::find_if(pair.first.begin(), pair.first.end(), [](char c) { return !std::isdigit(c); }) == pair.first.end();
148  if (is_number) {
149  label = vgettext("Player $side_num", utils::string_map{ { "side_num", pair.first } });
150  }
151  else {
152  label = pair.first;
153  }
154 
155  disp.labels().set_label(pair.second, label);
156  label_locs.insert(pair.second);
157  }
158  return label_locs;
159 }
160 
162 {
163  return selection_.find(loc) != selection_.end();
164 }
165 
167 {
168  return on_board_with_border(loc) ? selection_.insert(loc).second : false;
169 }
170 
171 bool editor_map::set_selection(const std::set<map_location>& area)
172 {
173  clear_selection();
174  for (const map_location& loc : area) {
175  if (!add_to_selection(loc))
176  return false;
177  }
178  return true;
179 }
180 
182 {
183  return selection_.erase(loc) != 0;
184 }
185 
187 {
188  selection_.clear();
189 }
190 
192 {
193  std::set<map_location> new_selection;
194  for (int x = -1; x < w() + 1; ++x) {
195  for (int y = -1; y < h() + 1; ++y) {
196  if (selection_.find(map_location(x, y)) == selection_.end()) {
197  new_selection.insert(map_location(x, y));
198  }
199  }
200  }
201  selection_.swap(new_selection);
202 }
203 
205 {
206  clear_selection();
208 }
209 
211 {
212  LOG_ED << selection_.size() << " " << total_width() * total_height() << "\n";
213  return static_cast<int>(selection_.size()) == total_width() * total_height();
214 }
215 
216 void editor_map::resize(int width, int height, int x_offset, int y_offset,
217  const t_translation::terrain_code & filler)
218 {
219  int old_w = w();
220  int old_h = h();
221  if (old_w == width && old_h == height && x_offset == 0 && y_offset == 0) {
222  return;
223  }
224 
225  // Determine the amount of resizing is required
226  const int left_resize = -x_offset;
227  const int right_resize = (width - old_w) + x_offset;
228  const int top_resize = -y_offset;
229  const int bottom_resize = (height - old_h) + y_offset;
230 
231  if(right_resize > 0) {
232  expand_right(right_resize, filler);
233  } else if(right_resize < 0) {
234  shrink_right(-right_resize);
235  }
236  if(bottom_resize > 0) {
237  expand_bottom(bottom_resize, filler);
238  } else if(bottom_resize < 0) {
239  shrink_bottom(-bottom_resize);
240  }
241  if(left_resize > 0) {
242  expand_left(left_resize, filler);
243  } else if(left_resize < 0) {
244  shrink_left(-left_resize);
245  }
246  if(top_resize > 0) {
247  expand_top(top_resize, filler);
248  } else if(top_resize < 0) {
249  shrink_top(-top_resize);
250  }
251 
252  // fix the starting positions
253  if(x_offset || y_offset) {
254  for (auto it = starting_positions_.left.begin(); it != starting_positions_.left.end(); ++it) {
255  starting_positions_.left.modify_data(it, [=](t_translation::coordinate & loc) { loc.add(-x_offset, -y_offset); });
256  }
257  }
258  sanity_check();
259 }
260 
261 gamemap editor_map::mask_to(const gamemap& target) const
262 {
263  if (target.w() != w() || target.h() != h()) {
264  throw editor_action_exception(_("The size of the target map is different from the current map"));
265  }
266  gamemap mask(target);
267  map_location iter;
268  for (iter.x = -border_size(); iter.x < w() + border_size(); ++iter.x) {
269  for (iter.y = -border_size(); iter.y < h() + border_size(); ++iter.y) {
270  if (target.get_terrain(iter) == get_terrain(iter)) {
272  }
273  }
274  }
275  return mask;
276 }
277 
278 bool editor_map::same_size_as(const gamemap& other) const
279 {
280  return h() == other.h()
281  && w() == other.w();
282 }
283 
285 {
286  t_translation::ter_map tiles_new(tiles_.w + count, tiles_.h);
287  w_ += count;
288  for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
289  for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
290  tiles_new.get(x, y) = tiles_.get(x, y);
291  }
292  }
293  for (int x = tiles_.w, x_end = tiles_.w + count; x != x_end; ++x) {
294  for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
295  tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles_.get(tiles_.w - 1, y) : filler;
296  }
297  }
298  tiles_ = std::move(tiles_new);
299 }
300 
302 {
303  t_translation::ter_map tiles_new(tiles_.w + count, tiles_.h);
304  w_ += count;
305  for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
306  for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
307  tiles_new.get(x + count, y) = tiles_.get(x, y);
308  }
309  }
310  for (int x = 0, x_end = count; x != x_end; ++x) {
311  for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
312  tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles_.get(0, y) : filler;
313  }
314  }
315  tiles_ = std::move(tiles_new);
316 }
317 
319 {
320  t_translation::ter_map tiles_new(tiles_.w, tiles_.h + count);
321  h_ += count;
322  for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
323  for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
324  tiles_new.get(x, y + count) = tiles_.get(x, y);
325  }
326  }
327  for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
328  for (int y = 0, y_end = count; y != y_end; ++y) {
329  tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles_.get(x, 0) : filler;
330  }
331  }
332  tiles_ = std::move(tiles_new);
333 }
334 
336 {
337  t_translation::ter_map tiles_new(tiles_.w, tiles_.h + count);
338  h_ += count;
339  for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
340  for (int y = 0, y_end = tiles_.h; y != y_end; ++y) {
341  tiles_new.get(x, y) = tiles_.get(x, y);
342  }
343  }
344  for (int x = 0, x_end = tiles_.w; x != x_end; ++x) {
345  for (int y = tiles_.h, y_end = tiles_.h + count; y != y_end; ++y) {
346  tiles_new.get(x, y) = filler == t_translation::NONE_TERRAIN ? tiles_.get(x, tiles_.h - 1) : filler;
347  }
348  }
349  tiles_ = std::move(tiles_new);
350 }
351 
353 {
354  if(count < 0 || count > tiles_.w) {
356  }
357  t_translation::ter_map tiles_new(tiles_.w - count, tiles_.h);
358  for (int x = 0, x_end = tiles_new.w; x != x_end; ++x) {
359  for (int y = 0, y_end = tiles_new.h; y != y_end; ++y) {
360  tiles_new.get(x, y) = tiles_.get(x, y);
361  }
362  }
363  w_ -= count;
364  tiles_ = std::move(tiles_new);
365 }
366 
368 {
369  if (count < 0 || count > tiles_.w) {
371  }
372  t_translation::ter_map tiles_new(tiles_.w - count, tiles_.h);
373  for (int x = 0, x_end = tiles_new.w; x != x_end; ++x) {
374  for (int y = 0, y_end = tiles_new.h; y != y_end; ++y) {
375  tiles_new.get(x, y) = tiles_.get(x + count, y);
376  }
377  }
378  w_ -= count;
379  tiles_ = std::move(tiles_new);
380 }
381 
383 {
384  if (count < 0 || count > tiles_.h) {
386  }
387  t_translation::ter_map tiles_new(tiles_.w, tiles_.h - count);
388  for (int x = 0, x_end = tiles_new.w; x != x_end; ++x) {
389  for (int y = 0, y_end = tiles_new.h; y != y_end; ++y) {
390  tiles_new.get(x, y) = tiles_.get(x, y + count);
391  }
392  }
393  h_ -= count;
394  tiles_ = std::move(tiles_new);
395 }
396 
398 {
399  if (count < 0 || count > tiles_.h) {
401  }
402  t_translation::ter_map tiles_new(tiles_.w, tiles_.h - count);
403  for (int x = 0, x_end = tiles_new.w; x != x_end; ++x) {
404  for (int y = 0, y_end = tiles_new.h; y != y_end; ++y) {
405  tiles_new.get(x, y) = tiles_.get(x, y);
406  }
407  }
408  h_ -= count;
409  tiles_ = std::move(tiles_new);
410 }
411 
412 
413 
414 } //end namespace editor
int total_width() const
Real width of the map, including borders.
Definition: map.hpp:99
bool on_board_with_border(const map_location &loc) const
Definition: map.cpp:374
void expand_bottom(int count, const t_translation::terrain_code &filler)
Definition: editor_map.cpp:335
std::vector< char_t > string
const terrain_code NONE_TERRAIN
Definition: translation.hpp:64
std::map< std::string, t_string > string_map
std::set< map_location > selection_
The selected hexes.
Definition: editor_map.hpp:204
std::set< map_location > set_starting_position_labels(display &disp)
Set labels for staring positions in the given display object.
Definition: editor_map.cpp:139
void shrink_top(int count)
Definition: editor_map.cpp:382
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
void get_adjacent_tiles(const map_location &a, map_location *res)
Function which, given a location, will place all adjacent locations in res.
Definition: location.hpp:299
#define LOG_ED
std::string user_message
The message for the user explaining what went wrong.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:55
void sanity_check()
Debugging aid.
Definition: editor_map.cpp:87
STL namespace.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
Base class for editor actions.
void resize(int width, int height, int x_offset, int y_offset, const t_translation::terrain_code &filler=t_translation::NONE_TERRAIN)
Resize the map.
Definition: editor_map.cpp:216
std::set< map_location > get_contiguous_terrain_tiles(const map_location &start) const
Get a contiguous set of tiles having the same terrain as the starting location.
Definition: editor_map.cpp:116
~editor_map()
editor_map destructor
Definition: editor_map.cpp:83
int total_height() const
Real height of the map, including borders.
Definition: map.hpp:102
void set_terrain(const map_location &loc, const t_translation::terrain_code &terrain, const terrain_type_data::merge_mode mode=terrain_type_data::BOTH, bool replace_if_failed=false)
Clobbers over the terrain at location 'loc', with the given terrain.
Definition: map.cpp:381
editor_map_load_exception wrap_exc(const char *type, const std::string &e_msg, const std::string &filename)
Exception wrapping utility.
Definition: editor_map.cpp:31
t_translation::terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:301
#define WRN_ED
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
void add(int x_diff, int y_diff)
Definition: location.hpp:121
bool everything_selected() const
Definition: editor_map.cpp:210
const terrain_code FOGGED
gamemap mask_to(const gamemap &target) const
A sort-of diff operation returning a mask that, when applied to the current editor_map, will transform it into the target map.
Definition: editor_map.cpp:261
const terrain_label * set_label(const map_location &loc, const t_string &text, const int creator=-1, const std::string &team="", const color_t color=font::NORMAL_COLOR, const bool visible_in_fog=true, const bool visible_in_shroud=false, const bool immutable=false, const std::string &category="", const t_string &tooltip="")
Definition: label.cpp:146
void expand_left(int count, const t_translation::terrain_code &filler)
Definition: editor_map.cpp:301
bool in_selection(const map_location &loc) const
Definition: editor_map.cpp:161
void invert_selection()
Invert the selection, i.e.
Definition: editor_map.cpp:191
bool same_size_as(const gamemap &other) const
A precondition to several map operations.
Definition: editor_map.cpp:278
int w() const
Effective map width.
Definition: map.hpp:90
Encapsulates the map of the game.
Definition: map.hpp:34
int border_size() const
Size of the map border.
Definition: map.hpp:96
map_display and display: classes which take care of displaying the map and game-data on the screen...
int w_
Sizes of the map area.
Definition: map.hpp:228
Manage the empty-palette in the editor.
Definition: action.cpp:29
void shrink_left(int count)
Definition: editor_map.cpp:367
static const ::config * terrain
The terrain used to create the cache.
Definition: minimap.cpp:133
bool add_to_selection(const map_location &loc)
Add a location to the selection.
Definition: editor_map.cpp:166
Encapsulates the map of the game.
Definition: location.hpp:40
Helper class, don't construct this directly.
static editor_map from_string(const config &terrain_cfg, const std::string &data)
Wrapper around editor_map(cfg, data) that catches possible exceptions and wraps them in a editor_map_...
Definition: editor_map.cpp:56
t_translation::ter_map tiles_
Definition: map.hpp:210
This class adds extra editor-specific functionality to a normal gamemap.
Definition: editor_map.hpp:69
int h() const
Effective map height.
Definition: map.hpp:93
editor_map(const config &terrain_cfg)
Empty map constructor.
Definition: editor_map.cpp:43
void expand_right(int count, const t_translation::terrain_code &filler)
Definition: editor_map.cpp:284
std::string write_game_map(const ter_map &map, const starting_positions &starting_positions, coordinate border_offset)
Write a gamemap in to a vector string.
void clear_selection()
Clear the selection.
Definition: editor_map.cpp:186
#define i
terrain_code & get(int x, int y)
Definition: translation.hpp:98
starting_positions starting_positions_
Definition: map.hpp:212
std::string vgettext(const char *msgid, const utils::string_map &symbols)
void select_all()
Select all map hexes.
Definition: editor_map.cpp:204
#define ERR_ED
void expand_top(int count, const t_translation::terrain_code &filler)
Definition: editor_map.cpp:318
std::string message
Definition: exceptions.hpp:31
map_labels & labels()
Definition: display.cpp:2490
#define e
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
mock_char c
int h_
Definition: map.hpp:229
void shrink_right(int count)
Definition: editor_map.cpp:352
bool set_selection(const std::set< map_location > &area)
Select the given area.
Definition: editor_map.cpp:171
EXIT_STATUS start(const config &game_conf, CVideo &video, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Definition: editor_main.cpp:28
bool remove_from_selection(const map_location &loc)
Remove a location to the selection.
Definition: editor_map.cpp:181
void shrink_bottom(int count)
Definition: editor_map.cpp:397