-
-
Notifications
You must be signed in to change notification settings - Fork 992
/
action.hpp
370 lines (328 loc) · 9.6 KB
/
action.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
/*
Copyright (C) 2008 - 2016 by Tomasz Sniatowski <kailoran@gmail.com>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Editor action classes. Some important points:
* - This is a polymorphic hierarchy of classes, so actions are usually passed around
* as editor_action pointers
* - The pointers can, in general, be null. Always check for null before doing anything.
* The helper functions perform_ that take a pointer do that.
* - The perform() functions can throw when an error occurs. Use smart pointers if you
* need to ensure the pointer is deleted.
*/
#ifndef EDITOR_ACTION_HPP
#define EDITOR_ACTION_HPP
#include "editor/action/action_base.hpp"
#include "editor/map/map_fragment.hpp"
namespace editor {
/**
* Replace contents of the entire map,
* Useful as a fallback undo method when something else would be impractical
*/
class editor_action_whole_map : public editor_action
{
public:
editor_action_whole_map(const editor_map& m)
: m_(m)
{
}
editor_action_whole_map* clone() const;
void perform_without_undo(map_context& m) const;
const char* get_name() const { return "whole_map"; }
protected:
editor_map m_;
};
/**
* Base class for actions that:
* 1) operate on an area
* 2) can be used as undo for a click-drag operation
* 3) can be extended so one undo action undos several actual drag actions
*/
class editor_action_extendable : public editor_action
{
public:
editor_action_extendable()
{
}
/**
* The crux of the extendable contract. This member function must be
* implemented so that the undo behavior is consistent, exactly the
* same as would be with separate undo actions for every part of
* the drag.
*/
virtual void extend(const editor_map& map, const std::set<map_location>& locs) = 0;
const char* get_name() const { return "extendable"; }
};
/**
* Container action wrapping several actions into one.
* The actions are performed in the order they are added,
* i.e. in the usual iteration order through the container.
*/
class editor_action_chain : public editor_action
{
public:
/**
* Create an empty action chain
*/
editor_action_chain() :
actions_()
{
}
editor_action_chain(const editor_action_chain& other);
editor_action_chain& operator=(const editor_action_chain& other);
editor_action_chain* clone() const;
/**
* Create an action chain from a deque of action pointers.
* Note: the action chain assumes ownership of the pointers.
*/
explicit editor_action_chain(std::deque<editor_action*> actions)
: actions_(actions)
{
}
/**
* Create an action chain by wrapping around a single action pointer.
* Note: the action chain assumes ownership of the pointer.
*/
explicit editor_action_chain(editor_action* action)
: actions_(1, action)
{
}
/**
* The destructor deletes all the owned action pointers
*/
~editor_action_chain();
/**
* Go through the chain and add up all the action counts
*/
int action_count() const;
/**
* Add an action at the end of the chain
*/
void append_action(editor_action* a);
/**
* Add an action at the beginning of the chain
*/
void prepend_action(editor_action* a);
/**
* @return true when there are no actions in the chain. Empty
* action chains should usually be discarded as to not keep
* "empty" actions around.
*/
bool empty() const;
/**
* Remove the last added action and return it, transferring
* ownership to the caller
*/
editor_action* pop_last_action();
/**
* Remove the first added action and return it, transferring
* ownership to the caller
*/
editor_action* pop_first_action();
/**
* Perform all the actions in order and create a undo action chain
*/
editor_action_chain* perform(map_context& m) const;
/**
* Perform all the actions in order
*/
void perform_without_undo(map_context& m) const;
const char* get_name() const { return "chain"; }
protected:
/**
* The action pointers owned by this action chain
*/
std::deque<editor_action*> actions_;
};
/**
* Base class for actions which act on a specified location (and possibly on other locations
* that can be derived from the staring hex)
*/
class editor_action_location : public editor_action
{
public:
editor_action_location(map_location loc)
: loc_(loc)
{
}
const char* get_name() const { return "location"; }
protected:
map_location loc_;
};
/** Base class for actions which in addition to acting on a hex,
* act with one terrain type, i.e. paint-related actions.
*/
class editor_action_location_terrain : public editor_action_location
{
public:
editor_action_location_terrain(map_location loc,
const t_translation::t_terrain & t)
: editor_action_location(loc), t_(t)
{
}
const char* get_name() const { return "location_terrain"; }
protected:
t_translation::t_terrain t_;
};
/**
* Base class for area-affecting actions
*/
class editor_action_area : public editor_action_extendable
{
public:
editor_action_area(const std::set<map_location>& area)
: area_(area)
{
}
void extend(const editor_map& map, const std::set<map_location>& locs);
const char* get_name() const { return "area"; }
protected:
std::set<map_location> area_;
};
/**
* Paste a map fragment into the map. No offset is used.
*/
class editor_action_paste : public editor_action_extendable
{
public:
editor_action_paste(const map_fragment& paste, const map_location& offset = map_location::ZERO())
: offset_(offset), paste_(paste)
{
}
editor_action_paste* clone() const;
editor_action_paste* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
void extend(const editor_map& map, const std::set<map_location>& locs);
const char* get_name() const { return "paste"; }
protected:
map_location offset_;
map_fragment paste_;
};
/**
* Paint the same terrain on a number of locations on the map.
*/
class editor_action_paint_area : public editor_action_area
{
public:
editor_action_paint_area(const std::set<map_location>& area,
const t_translation::t_terrain & t, bool one_layer=false)
: editor_action_area(area), t_(t), one_layer_(one_layer)
{
}
editor_action_paint_area* clone() const;
editor_action_paste* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
const char* get_name() const { return "paint_area"; }
protected:
t_translation::t_terrain t_;
bool one_layer_;
};
/**
* Flood fill. Somewhat redundant with paint_area.
*/
class editor_action_fill : public editor_action_location_terrain
{
public:
editor_action_fill(map_location loc,
const t_translation::t_terrain & t, bool one_layer=false)
: editor_action_location_terrain(loc, t), one_layer_(one_layer)
{
}
editor_action_fill* clone() const;
editor_action_paint_area* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
const char* get_name() const { return "fill"; }
protected:
bool one_layer_;
};
/**
* Set starting position action
*/
class editor_action_starting_position : public editor_action_location
{
public:
editor_action_starting_position(map_location loc, std::string loc_id)
: editor_action_location(loc), loc_id_(loc_id)
{
}
editor_action_starting_position* clone() const;
editor_action* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
const char* get_name() const { return "starting_pos"; }
protected:
std::string loc_id_;
};
/**
* Resize the map. The offsets specify, indirectly, the direction of expanding/shrinking,
* and fill=NONE enables copying of edge terrain instead of filling.
*/
class editor_action_resize_map : public editor_action
{
public:
editor_action_resize_map(int x_size, int y_size, int x_offset, int y_offset,
const t_translation::t_terrain & fill = t_translation::NONE_TERRAIN)
: x_size_(x_size), y_size_(y_size), x_offset_(x_offset), y_offset_(y_offset), fill_(fill)
{
}
editor_action_resize_map* clone() const;
void perform_without_undo(map_context& mc) const;
const char* get_name() const { return "resize"; }
protected:
int x_size_;
int y_size_;
int x_offset_;
int y_offset_;
t_translation::t_terrain fill_;
};
class editor_action_apply_mask : public editor_action
{
public:
editor_action_apply_mask(const gamemap& mask)
: mask_(mask)
{
}
editor_action_apply_mask* clone() const;
void perform_without_undo(map_context& mc) const;
const char* get_name() const { return "apply_mask"; }
private:
gamemap mask_;
};
class editor_action_create_mask : public editor_action
{
public:
editor_action_create_mask(const editor_map& target)
: target_(target)
{
}
editor_action_create_mask* clone() const;
void perform_without_undo(map_context& mc) const;
const char* get_name() const { return "create_mask"; }
private:
editor_map target_;
};
/**
* Randomize terrain in an area
*/
class editor_action_shuffle_area : public editor_action_area
{
public:
editor_action_shuffle_area(const std::set<map_location>& area)
: editor_action_area(area)
{
}
editor_action_shuffle_area* clone() const;
editor_action_paste* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
const char* get_name() const { return "shuffle_area"; }
};
} //end namespace editor
#endif