The Battle for Wesnoth  1.19.5+dev
action.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
3  by Tomasz Sniatowski <kailoran@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Editor action classes
19  */
20 #define GETTEXT_DOMAIN "wesnoth-editor"
21 
22 #include "editor/action/action.hpp"
23 
25 #include "gettext.hpp"
26 #include "random.hpp"
27 
28 #include <memory>
29 
30 namespace editor
31 {
34 
36  : id_(next_id_++)
37 {
39 
40 #ifdef EDITOR_DEBUG_ACTION_LIFETIME
41  LOG_ED << "Action " << std::setw(2) << id_ << " ctor " << this << " (count is " << instance_count;
42 #endif
43 }
44 
46 {
48 
49 #ifdef EDITOR_DEBUG_ACTION_LIFETIME
50  LOG_ED << "Action " << std::setw(2) << id_ << " dtor " << this << " (count is " << instance_count;
51 #endif
52 }
53 
55 {
56  return 1;
57 }
58 
59 std::string editor_action::get_description() const
60 {
61  return "Unknown action";
62 }
63 
64 std::unique_ptr<editor_action> editor_action::perform(map_context& mc) const
65 {
66  auto undo = std::make_unique<editor_action_whole_map>(mc.map());
68  return undo;
69 }
70 
71 IMPLEMENT_ACTION(whole_map)
72 
73 void editor_action_whole_map::perform_without_undo(map_context& mc) const
74 {
75  mc.set_map(m_);
76 }
77 
79  : editor_action()
80  , actions_()
81 {
82  for(const auto& a : other.actions_) {
83  actions_.push_back(a->clone());
84  }
85 }
86 
88 {
89  if(this == &other) {
90  return *this;
91  }
92 
93  actions_.clear();
94 
95  for(const auto& a : other.actions_) {
96  actions_.push_back(a->clone());
97  }
98 
99  return *this;
100 }
101 
102 IMPLEMENT_ACTION(chain)
103 
104 int editor_action_chain::action_count() const
105 {
106  int count = 0;
107  for(const auto& a : actions_) {
108  if(a) {
109  count += a->action_count();
110  }
111  }
112 
113  return count;
114 }
115 
116 void editor_action_chain::append_action(std::unique_ptr<editor_action> a)
117 {
118  actions_.push_back(std::move(a));
119 }
120 
121 void editor_action_chain::prepend_action(std::unique_ptr<editor_action> a)
122 {
123  actions_.push_front(std::move(a));
124 }
125 
127 {
128  return actions_.empty();
129 }
130 
131 std::unique_ptr<editor_action> editor_action_chain::pop_last_action()
132 {
133  if(empty()) {
134  throw editor_action_exception("pop_last_action requested on an empty action_chain");
135  }
136 
137  auto last = std::move(actions_.back());
138  actions_.pop_back();
139  return last;
140 }
141 
142 std::unique_ptr<editor_action> editor_action_chain::pop_first_action()
143 {
144  if(empty()) {
145  throw editor_action_exception("pop_first_action requested on an empty action_chain");
146  }
147 
148  auto first = std::move(actions_.front());
149  actions_.pop_front();
150  return first;
151 }
152 
153 std::unique_ptr<editor_action> editor_action_chain::perform(map_context& mc) const
154 {
155  auto undo = std::make_unique<editor_action_chain>();
156  for(auto& a : actions_) {
157  if(a != nullptr) {
158  undo->append_action(a->perform(mc));
159  }
160  }
161 
162  std::reverse(undo->actions_.begin(), undo->actions_.end());
163  return undo;
164 }
166 {
167  for(const auto& a : actions_) {
168  if(a != nullptr) {
169  a->perform_without_undo(mc);
170  }
171  }
172 }
173 
174 void editor_action_area::extend(const editor_map& /*map*/, const std::set<map_location>& locs)
175 {
176  area_.insert(locs.begin(), locs.end());
177 }
178 
179 IMPLEMENT_ACTION(paste)
180 
181 void editor_action_paste::extend(const editor_map& map, const std::set<map_location>& locs)
182 {
183  paste_.add_tiles(map, locs);
184 }
185 
186 std::unique_ptr<editor_action> editor_action_paste::perform(map_context& mc) const
187 {
189  auto undo = std::make_unique<editor_action_paste>(mf);
190 
192  return undo;
193 }
194 
196 {
197  paste_.paste_into(mc.map(), offset_);
200 }
201 
202 IMPLEMENT_ACTION(paint_area)
203 
204 std::unique_ptr<editor_action> editor_action_paint_area::perform(map_context& mc) const
205 {
206  map_fragment mf(mc.map(), area_);
207  auto undo = std::make_unique<editor_action_paste>(mf);
208 
209  perform_without_undo(mc);
210  return undo;
211 }
212 
214 {
217 }
218 
220 
221 std::unique_ptr<editor_action> editor_action_fill::perform(map_context& mc) const
222 {
223  std::set<map_location> to_fill = mc.map().get_contiguous_terrain_tiles(loc_);
224  auto undo = std::make_unique<editor_action_paint_area>(to_fill, mc.map().get_terrain(loc_));
225 
226  mc.draw_terrain(t_, to_fill, one_layer_);
227  mc.set_needs_terrain_rebuild();
228 
229  return undo;
230 }
231 
233 {
234  std::set<map_location> to_fill = mc.map().get_contiguous_terrain_tiles(loc_);
235  mc.draw_terrain(t_, to_fill, one_layer_);
237 }
238 
239 IMPLEMENT_ACTION(starting_position)
240 
241 std::unique_ptr<editor_action> editor_action_starting_position::perform(map_context& mc) const
242 {
243  std::unique_ptr<editor_action> undo;
244 
245  const std::string* old_loc_id = mc.map().is_special_location(loc_);
246  map_location old_loc = mc.map().special_location(loc_id_);
247 
248  if(old_loc_id != nullptr) {
249  // If another player was starting at the location, we actually perform two actions, so the undo is an
250  // action_chain.
251  auto undo_chain = std::make_unique<editor_action_chain>();
252 
253  undo_chain->append_action(std::make_unique<editor_action_starting_position>(loc_, *old_loc_id));
254  undo_chain->append_action(std::make_unique<editor_action_starting_position>(old_loc, loc_id_));
255 
256  undo = std::move(undo_chain);
257 
258  LOG_ED << "ssp actual: " << *old_loc_id << " to " << map_location();
259 
260  mc.map().set_special_location(*old_loc_id, map_location());
261  } else {
262  undo = std::make_unique<editor_action_starting_position>(old_loc, loc_id_);
263  }
264 
265  LOG_ED << "ssp actual: " << loc_id_ << " to " << loc_;
266 
267  mc.map().set_special_location(loc_id_, loc_);
268  mc.set_needs_labels_reset();
269 
270  return undo;
271 }
272 
274 {
275  const std::string* old_id = mc.map().is_special_location(loc_);
276  if(old_id != nullptr) {
277  mc.map().set_special_location(*old_id, map_location());
278  }
279 
282 }
283 
284 IMPLEMENT_ACTION(resize_map)
285 
286 void editor_action_resize_map::perform_without_undo(map_context& mc) const
287 {
288  mc.map().resize(x_size_, y_size_, x_offset_, y_offset_, fill_);
289  mc.set_needs_reload();
290 }
291 
292 IMPLEMENT_ACTION(apply_mask)
293 
294 void editor_action_apply_mask::perform_without_undo(map_context& mc) const
295 {
296  mc.map().overlay(mask_, {0, 0, wml_loc()});
297  mc.set_needs_terrain_rebuild();
298 }
299 
300 IMPLEMENT_ACTION(create_mask)
301 
302 void editor_action_create_mask::perform_without_undo(map_context& mc) const
303 {
304  mc.set_map(editor_map(mc.map().mask_to(target_)));
305  mc.set_needs_terrain_rebuild();
306 }
307 
308 IMPLEMENT_ACTION(shuffle_area)
309 
310 std::unique_ptr<editor_action> editor_action_shuffle_area::perform(map_context& mc) const
311 {
312  map_fragment mf(mc.map(), area_);
313  auto undo = std::make_unique<editor_action_paste>(mf);
314  perform_without_undo(mc);
315  return undo;
316 }
317 
319 {
320  std::vector<map_location> shuffle;
321 
322  std::copy(area_.begin(), area_.end(), std::inserter(shuffle, shuffle.begin()));
324 
325  std::vector<map_location>::const_iterator shuffle_it = shuffle.begin();
326  std::set<map_location>::const_iterator orig_it = area_.begin();
327 
328  while(orig_it != area_.end()) {
329  t_translation::terrain_code tmp = mc.map().get_terrain(*orig_it);
330 
331  mc.draw_terrain(mc.map().get_terrain(*shuffle_it), *orig_it);
332  mc.draw_terrain(tmp, *shuffle_it);
333 
334  ++orig_it;
335  ++shuffle_it;
336  }
337 
339 }
340 
341 } // end namespace editor
#define IMPLEMENT_ACTION(id)
Helper macro to implement common action methods.
void extend(const editor_map &map, const std::set< map_location > &locs) override
The crux of the extendable contract.
Definition: action.cpp:174
std::set< map_location > area_
Definition: action.hpp:236
Container action wrapping several actions into one.
Definition: action.hpp:88
std::unique_ptr< editor_action > pop_last_action()
Remove the last added action and return it, transferring ownership to the caller.
Definition: action.cpp:131
editor_action_chain()
Create an empty action chain.
Definition: action.hpp:93
void perform_without_undo(map_context &m) const override
Perform all the actions in order.
Definition: action.cpp:165
std::unique_ptr< editor_action > pop_first_action()
Remove the first added action and return it, transferring ownership to the caller.
Definition: action.cpp:142
editor_action_chain & operator=(const editor_action_chain &other)
Definition: action.cpp:87
void append_action(std::unique_ptr< editor_action > a)
Add an action at the end of the chain.
Definition: action.cpp:116
int action_count() const override
Go through the chain and add up all the action counts.
Definition: action.cpp:104
std::deque< std::unique_ptr< editor_action > > actions_
The action pointers owned by this action chain.
Definition: action.hpp:169
void prepend_action(std::unique_ptr< editor_action > a)
Add an action at the beginning of the chain.
Definition: action.cpp:121
std::unique_ptr< editor_action > perform(map_context &m) const override
Perform all the actions in order and create a undo action chain.
Definition: action.cpp:153
void perform_without_undo(map_context &mc) const override
Perform the action without creating an undo action.
Definition: action.cpp:232
t_translation::terrain_code t_
Definition: action.hpp:213
Paint the same terrain on a number of locations on the map.
Definition: action.hpp:266
void perform_without_undo(map_context &mc) const override
Perform the action without creating an undo action.
Definition: action.cpp:213
t_translation::terrain_code t_
Definition: action.hpp:282
Paste a map fragment into the map.
Definition: action.hpp:243
void perform_without_undo(map_context &mc) const override
Perform the action without creating an undo action.
Definition: action.cpp:195
std::unique_ptr< editor_action > perform(map_context &mc) const override
Perform the action, returning an undo action that, when performed, shall reverse any effects of this ...
Definition: action.cpp:186
Randomize terrain in an area.
Definition: action.hpp:399
void perform_without_undo(map_context &mc) const override
Perform the action without creating an undo action.
Definition: action.cpp:318
Set starting position action, sets location ids (both for starting locations and for non-starting loc...
Definition: action.hpp:313
void perform_without_undo(map_context &mc) const override
Perform the action without creating an undo action.
Definition: action.cpp:273
Replace contents of the entire map, Useful as a fallback undo method when something else would be imp...
Definition: action.hpp:39
Base class for all editor actions.
Definition: action_base.hpp:42
static int instance_count_
virtual void perform_without_undo(map_context &) const =0
Perform the action without creating an undo action.
virtual std::unique_ptr< editor_action > perform(map_context &) const
Perform the action, returning an undo action that, when performed, shall reverse any effects of this ...
Definition: action.cpp:64
virtual ~editor_action()
Definition: action.cpp:45
virtual std::string get_description() const
A textual description of the action.
Definition: action.cpp:59
virtual int action_count() const
Definition: action.cpp:54
This class adds extra editor-specific functionality to a normal gamemap.
Definition: editor_map.hpp:70
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:115
This class wraps around a map to provide a concise interface for the editor to work with.
Definition: map_context.hpp:63
void set_needs_labels_reset(bool value=true)
Setter for the labels reset flag.
void draw_terrain(const t_translation::terrain_code &terrain, const map_location &loc, bool one_layer_only=false)
Draw a terrain on a single location on the map.
virtual const editor_map & map() const override
Const map accessor.
void set_needs_terrain_rebuild(bool value=true)
Setter for the terrain rebuild flag.
void add_changed_location(const map_location &loc)
A map fragment – a collection of locations and information abut them.
std::set< map_location > get_offset_area(const map_location &offset) const
Get the area covered by this map fragment, shifted by an offset.
void paste_into(gamemap &map, const map_location &loc) const
Paste the map fragment into the map, treating loc as the (0,0) point (offset).
terrain_code get_terrain(const map_location &loc) const
Looks up terrain at a particular location.
Definition: map.cpp:302
void set_special_location(const std::string &id, const map_location &loc)
Definition: map.cpp:363
const std::string * is_special_location(const map_location &loc) const
returns the name of the special location at position loc, null if no such location exists.
Definition: map.cpp:357
static rng & default_instance()
Definition: random.cpp:73
Editor action classes.
#define LOG_ED
map_location loc_
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:176
void fill(const SDL_Rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Definition: draw.cpp:50
Manage the empty-palette in the editor.
Definition: action.cpp:31
std::vector< game_tip > shuffle(const std::vector< game_tip > &tips)
Shuffles the tips.
Definition: tips.cpp:48
Encapsulates the map of the game.
Definition: location.hpp:45
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:49