Merge lp:~widelands-dev/widelands/editor-resize-map into lp:widelands
- editor-resize-map
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 9072 |
Proposed branch: | lp:~widelands-dev/widelands/editor-resize-map |
Merge into: | lp:widelands |
Diff against target: |
1162 lines (+649/-119) 16 files modified
src/editor/CMakeLists.txt (+4/-0) src/editor/editorinteractive.cc (+2/-2) src/editor/editorinteractive.h (+6/-2) src/editor/tools/action_args.h (+12/-0) src/editor/tools/history.cc (+1/-0) src/editor/tools/resize_tool.cc (+99/-0) src/editor/tools/resize_tool.h (+76/-0) src/editor/ui_menus/main_menu_new_map.cc (+23/-37) src/editor/ui_menus/main_menu_new_map.h (+3/-3) src/editor/ui_menus/main_menu_random_map.cc (+40/-47) src/editor/ui_menus/main_menu_random_map.h (+3/-5) src/editor/ui_menus/tool_menu.cc (+23/-10) src/editor/ui_menus/tool_resize_options_menu.cc (+108/-0) src/editor/ui_menus/tool_resize_options_menu.h (+48/-0) src/logic/map.cc (+169/-5) src/logic/map.h (+32/-8) |
To merge this branch: | bzr merge lp:~widelands-dev/widelands/editor-resize-map |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
GunChleoc | Approve | ||
Review via email: mp+365638@code.launchpad.net |
Commit message
Add an editor tool to change the map size
Description of the change
This is for b21.
Usage:
· Tool Menu → Resize
· Set the new map size
· Click on the map field where to split the map
New rows/columns will be inserted at the clicked spot. The field itself will then be located on the southeastern corner of the inserted rectangle of new fields. When making the map smaller, rows/columns south and east of the clicked field will be deleted.
bunnybot (widelandsofficial) wrote : | # |
GunChleoc (gunchleoc) wrote : | # |
First round of code review done. Not tested yet.
Benedikt Straub (nordfriese) wrote : | # |
Thanks for the review, implemented your suggestions
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 4695. State: passed. Details: https:/
Appveyor build 4481. State: success. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
Changes LGTM :)
Not tested yet.
GunChleoc (gunchleoc) wrote : | # |
I have given this a very quick spin.
I don't think that it is obvious to the user that they need to click on the map after selecting the values. Best add a Multilinetextarea with a hint.
I think it would also be good to have dropdown menus for the map size rather than spin boxes - selecting them will be much faster that way. You could put this into a separate class and use it everywhere in the editor where map sized are being set.
Benedikt Straub (nordfriese) wrote : | # |
OK, added the hint and replaced spinners with dropdowns in the Resize Tool options and the New Map and Random Map menus. The large code blocks for setting the initial values are now shorter and more intuitive, I don´t think we would gain much by making a new class for it.
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 4708. State: failed. Details: https:/
Appveyor build 4494. State: success. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
Changes look good. I have done some testing with a few random maps - no issues :)
GunChleoc (gunchleoc) wrote : | # |
Transient failure on Travis
@bunnybot merge force
bunnybot (widelandsofficial) wrote : | # |
Error merging this proposal:
Output:
stdout:
stderr:
+N data/images/
+N data/images/
+N src/editor/
+N src/editor/
+N src/editor/
+N src/editor/
M src/editor/
M src/editor/
M src/editor/
M src/editor/
M src/editor/
M src/editor/
M src/editor/
M src/editor/
M src/editor/
M src/editor/
M src/logic/map.cc
M src/logic/map.h
Text conflict in src/editor/
1 conflicts encountered.
bunnybot (widelandsofficial) wrote : | # |
Continuous integration builds have changed state:
Travis build 4766. State: errored. Details: https:/
Appveyor build 4550. State: success. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
Transient failure on Travis
@bunnybot merge
GunChleoc (gunchleoc) wrote : | # |
@bunnybot merge force
bunnybot (widelandsofficial) wrote : | # |
Refusing to merge, since Travis is not green. Use @bunnybot merge force for merging anyways.
Travis build 4766. State: errored. Details: https:/
GunChleoc (gunchleoc) wrote : | # |
@bunnybot merge force
Preview Diff
1 | === added file 'data/images/wui/editor/editor_menu_tool_resize.png' |
2 | Binary files data/images/wui/editor/editor_menu_tool_resize.png 1970-01-01 00:00:00 +0000 and data/images/wui/editor/editor_menu_tool_resize.png 2019-04-23 14:01:41 +0000 differ |
3 | === added file 'data/images/wui/editor/fsel_editor_resize.png' |
4 | Binary files data/images/wui/editor/fsel_editor_resize.png 1970-01-01 00:00:00 +0000 and data/images/wui/editor/fsel_editor_resize.png 2019-04-23 14:01:41 +0000 differ |
5 | === modified file 'src/editor/CMakeLists.txt' |
6 | --- src/editor/CMakeLists.txt 2018-11-04 17:56:37 +0000 |
7 | +++ src/editor/CMakeLists.txt 2019-04-23 14:01:41 +0000 |
8 | @@ -30,6 +30,8 @@ |
9 | tools/place_critter_tool.h |
10 | tools/place_immovable_tool.cc |
11 | tools/place_immovable_tool.h |
12 | + tools/resize_tool.cc |
13 | + tools/resize_tool.h |
14 | tools/set_height_tool.cc |
15 | tools/set_height_tool.h |
16 | tools/set_origin_tool.cc |
17 | @@ -79,6 +81,8 @@ |
18 | ui_menus/tool_place_critter_options_menu.h |
19 | ui_menus/tool_place_immovable_options_menu.cc |
20 | ui_menus/tool_place_immovable_options_menu.h |
21 | + ui_menus/tool_resize_options_menu.cc |
22 | + ui_menus/tool_resize_options_menu.h |
23 | ui_menus/tool_set_terrain_options_menu.cc |
24 | ui_menus/tool_set_terrain_options_menu.h |
25 | ui_menus/toolsize_menu.cc |
26 | |
27 | === modified file 'src/editor/editorinteractive.cc' |
28 | --- src/editor/editorinteractive.cc 2019-02-27 17:19:00 +0000 |
29 | +++ src/editor/editorinteractive.cc 2019-04-23 14:01:41 +0000 |
30 | @@ -72,7 +72,7 @@ |
31 | is_painting_(false), |
32 | undo_(nullptr), |
33 | redo_(nullptr), |
34 | - tools_(new Tools()), |
35 | + tools_(new Tools(e.map())), |
36 | history_(nullptr) // history needs the undo/redo buttons |
37 | { |
38 | add_toolbar_button("wui/menus/menu_toggle_menu", "menu", _("Main menu"), &mainmenu_, true); |
39 | @@ -652,7 +652,7 @@ |
40 | undo_->set_enabled(false); |
41 | redo_->set_enabled(false); |
42 | |
43 | - tools_.reset(new Tools()); |
44 | + tools_.reset(new Tools(egbase().map())); |
45 | select_tool(tools_->info, EditorTool::First); |
46 | set_sel_radius(0); |
47 | |
48 | |
49 | === modified file 'src/editor/editorinteractive.h' |
50 | --- src/editor/editorinteractive.h 2019-02-23 11:00:49 +0000 |
51 | +++ src/editor/editorinteractive.h 2019-04-23 14:01:41 +0000 |
52 | @@ -29,6 +29,7 @@ |
53 | #include "editor/tools/noise_height_tool.h" |
54 | #include "editor/tools/place_critter_tool.h" |
55 | #include "editor/tools/place_immovable_tool.h" |
56 | +#include "editor/tools/resize_tool.h" |
57 | #include "editor/tools/set_origin_tool.h" |
58 | #include "editor/tools/set_port_space_tool.h" |
59 | #include "editor/tools/set_starting_pos_tool.h" |
60 | @@ -49,7 +50,7 @@ |
61 | class EditorInteractive : public InteractiveBase { |
62 | public: |
63 | struct Tools { |
64 | - Tools() |
65 | + Tools(const Widelands::Map& map) |
66 | : current_pointer(&info), |
67 | use_tool(EditorTool::First), |
68 | increase_height(decrease_height, set_height), |
69 | @@ -58,7 +59,8 @@ |
70 | place_critter(delete_critter), |
71 | increase_resources(decrease_resources, set_resources), |
72 | set_port_space(unset_port_space), |
73 | - set_origin() { |
74 | + set_origin(), |
75 | + resize(map.get_width(), map.get_height()) { |
76 | } |
77 | EditorTool& current() const { |
78 | return *current_pointer; |
79 | @@ -83,6 +85,7 @@ |
80 | EditorSetPortSpaceTool set_port_space; |
81 | EditorUnsetPortSpaceTool unset_port_space; |
82 | EditorSetOriginTool set_origin; |
83 | + EditorResizeTool resize; |
84 | }; |
85 | explicit EditorInteractive(Widelands::EditorGameBase&); |
86 | |
87 | @@ -162,6 +165,7 @@ |
88 | UI::UniqueWindow::Registry immovablemenu_; |
89 | UI::UniqueWindow::Registry crittermenu_; |
90 | UI::UniqueWindow::Registry resourcesmenu_; |
91 | + UI::UniqueWindow::Registry resizemenu_; |
92 | UI::UniqueWindow::Registry helpmenu_; |
93 | |
94 | UI::Button* toggle_buildhelp_; |
95 | |
96 | === modified file 'src/editor/tools/action_args.h' |
97 | --- src/editor/tools/action_args.h 2019-02-23 11:00:49 +0000 |
98 | +++ src/editor/tools/action_args.h 2019-04-23 14:01:41 +0000 |
99 | @@ -21,9 +21,13 @@ |
100 | #define WL_EDITOR_TOOLS_ACTION_ARGS_H |
101 | |
102 | #include <list> |
103 | +#include <map> |
104 | +#include <set> |
105 | #include <string> |
106 | +#include <vector> |
107 | |
108 | #include "logic/field.h" |
109 | +#include "logic/map.h" |
110 | #include "logic/widelands_geometry.h" |
111 | |
112 | namespace Widelands { |
113 | @@ -52,12 +56,19 @@ |
114 | std::list<Widelands::Field::Height> original_heights; // change height tool |
115 | Widelands::DescriptionIndex current_resource; // resources change tools |
116 | Widelands::ResourceAmount set_to; // resources change tools |
117 | + Widelands::Extent new_map_size; // resize tool |
118 | |
119 | struct ResourceState { |
120 | Widelands::FCoords location; |
121 | Widelands::DescriptionIndex idx; |
122 | Widelands::ResourceAmount amount; |
123 | }; |
124 | + struct ResizeHistory { |
125 | + Widelands::Extent old_map_size = Widelands::Extent(0, 0); |
126 | + std::map<Widelands::Coords, Widelands::FieldData> deleted_fields; |
127 | + std::set<Widelands::Coords> port_spaces; |
128 | + std::vector<Widelands::Coords> starting_positions; |
129 | + }; |
130 | |
131 | std::list<ResourceState> original_resource; // resources set tool |
132 | std::list<const Widelands::BobDescr*> old_bob_type, new_bob_type; // bob change tools |
133 | @@ -65,6 +76,7 @@ |
134 | std::list<Widelands::DescriptionIndex> new_immovable_types; // immovable change tools |
135 | Widelands::HeightInterval interval; // noise height tool |
136 | std::list<Widelands::DescriptionIndex> terrain_type, original_terrain_type; // set terrain tool |
137 | + ResizeHistory resized; // resize tool |
138 | |
139 | std::list<EditorToolAction*> draw_actions; // draw tool |
140 | |
141 | |
142 | === modified file 'src/editor/tools/history.cc' |
143 | --- src/editor/tools/history.cc 2019-03-10 06:34:41 +0000 |
144 | +++ src/editor/tools/history.cc 2019-04-23 14:01:41 +0000 |
145 | @@ -35,6 +35,7 @@ |
146 | change_by(0), |
147 | current_resource(0), |
148 | set_to(0), |
149 | + new_map_size(0, 0), |
150 | interval(0, 0), |
151 | refcount(0) { |
152 | } |
153 | |
154 | === added file 'src/editor/tools/resize_tool.cc' |
155 | --- src/editor/tools/resize_tool.cc 1970-01-01 00:00:00 +0000 |
156 | +++ src/editor/tools/resize_tool.cc 2019-04-23 14:01:41 +0000 |
157 | @@ -0,0 +1,99 @@ |
158 | +/* |
159 | + * Copyright (C) 2002-2019 by the Widelands Development Team |
160 | + * |
161 | + * This program is free software; you can redistribute it and/or |
162 | + * modify it under the terms of the GNU General Public License |
163 | + * as published by the Free Software Foundation; either version 2 |
164 | + * of the License, or (at your option) any later version. |
165 | + * |
166 | + * This program is distributed in the hope that it will be useful, |
167 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
168 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
169 | + * GNU General Public License for more details. |
170 | + * |
171 | + * You should have received a copy of the GNU General Public License |
172 | + * along with this program; if not, write to the Free Software |
173 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
174 | + * |
175 | + */ |
176 | + |
177 | +#include "editor/tools/resize_tool.h" |
178 | + |
179 | +#include "editor/editorinteractive.h" |
180 | +#include "logic/field.h" |
181 | +#include "logic/widelands_geometry.h" |
182 | + |
183 | +int32_t EditorResizeTool::handle_click_impl(const Widelands::World& world, |
184 | + const Widelands::NodeAndTriangle<>& center, |
185 | + EditorInteractive& parent, |
186 | + EditorActionArgs* args, |
187 | + Widelands::Map* map) { |
188 | + Widelands::EditorGameBase& egbase = parent.egbase(); |
189 | + |
190 | + args->resized.old_map_size = map->extent(); |
191 | + args->resized.port_spaces.clear(); |
192 | + args->resized.starting_positions.clear(); |
193 | + for (const Widelands::Coords& ps : map->get_port_spaces()) { |
194 | + args->resized.port_spaces.insert(Widelands::Coords(ps)); |
195 | + } |
196 | + for (uint8_t i = 1; i <= map->get_nrplayers(); ++i) { |
197 | + args->resized.starting_positions.push_back(map->get_starting_pos(i)); |
198 | + } |
199 | + |
200 | + args->resized.deleted_fields = map->resize(egbase, center.node, args->new_map_size.w, args->new_map_size.h); |
201 | + |
202 | + map->recalc_whole_map(world); |
203 | + return 0; |
204 | +} |
205 | + |
206 | +int32_t EditorResizeTool::handle_undo_impl( |
207 | + const Widelands::World& world, |
208 | + const Widelands::NodeAndTriangle<Widelands::Coords>& center, |
209 | + EditorInteractive& parent, |
210 | + EditorActionArgs* args, |
211 | + Widelands::Map* map) { |
212 | + Widelands::EditorGameBase& egbase = parent.egbase(); |
213 | + |
214 | + map->resize(egbase, center.node, args->resized.old_map_size.w, args->resized.old_map_size.h); |
215 | + |
216 | + for (const auto& it : args->resized.deleted_fields) { |
217 | + const Widelands::FCoords f = map->get_fcoords(it.first); |
218 | + const Widelands::FieldData data = it.second; |
219 | + |
220 | + if (Widelands::BaseImmovable* imm = f.field->get_immovable()) { |
221 | + imm->remove(egbase); |
222 | + } |
223 | + for (Widelands::Bob* bob = f.field->get_first_bob(); bob; bob = bob->get_next_bob()) { |
224 | + bob->remove(egbase); |
225 | + } |
226 | + |
227 | + f.field->set_height(data.height); |
228 | + f.field->set_terrains(data.terrains); |
229 | + map->initialize_resources(f, data.resources, data.resource_amount); |
230 | + |
231 | + if (!data.immovable.empty()) { |
232 | + egbase.create_immovable_with_name(f, data.immovable, |
233 | + Widelands::MapObjectDescr::OwnerType::kWorld, nullptr, nullptr); |
234 | + } |
235 | + for (const std::string& bob : data.bobs) { |
236 | + egbase.create_critter(f, bob); |
237 | + } |
238 | + } |
239 | + |
240 | + for (const Widelands::Coords& c : args->resized.port_spaces) { |
241 | + map->set_port_space(world, c, true, true); |
242 | + } |
243 | + for (uint8_t i = 1; i <= map->get_nrplayers(); ++i) { |
244 | + map->set_starting_pos(i, args->resized.starting_positions[i - 1]); |
245 | + } |
246 | + |
247 | + map->recalc_whole_map(world); |
248 | + return 0; |
249 | +} |
250 | + |
251 | +EditorActionArgs EditorResizeTool::format_args_impl(EditorInteractive& parent) { |
252 | + EditorActionArgs a(parent); |
253 | + a.new_map_size = Widelands::Extent(width_, height_); |
254 | + return a; |
255 | +} |
256 | + |
257 | |
258 | === added file 'src/editor/tools/resize_tool.h' |
259 | --- src/editor/tools/resize_tool.h 1970-01-01 00:00:00 +0000 |
260 | +++ src/editor/tools/resize_tool.h 2019-04-23 14:01:41 +0000 |
261 | @@ -0,0 +1,76 @@ |
262 | +/* |
263 | + * Copyright (C) 2002-2019 by the Widelands Development Team |
264 | + * |
265 | + * This program is free software; you can redistribute it and/or |
266 | + * modify it under the terms of the GNU General Public License |
267 | + * as published by the Free Software Foundation; either version 2 |
268 | + * of the License, or (at your option) any later version. |
269 | + * |
270 | + * This program is distributed in the hope that it will be useful, |
271 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
272 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
273 | + * GNU General Public License for more details. |
274 | + * |
275 | + * You should have received a copy of the GNU General Public License |
276 | + * along with this program; if not, write to the Free Software |
277 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
278 | + * |
279 | + */ |
280 | + |
281 | +#ifndef WL_EDITOR_TOOLS_RESIZE_TOOL_H |
282 | +#define WL_EDITOR_TOOLS_RESIZE_TOOL_H |
283 | + |
284 | +#include "editor/tools/tool.h" |
285 | + |
286 | +/// Resize the map |
287 | +struct EditorResizeTool : public EditorTool { |
288 | + EditorResizeTool(int16_t width, int16_t height) : EditorTool(*this, *this), width_(width), height_(height) { |
289 | + } |
290 | + |
291 | + /** |
292 | + * Change the map size |
293 | + */ |
294 | + int32_t handle_click_impl(const Widelands::World& world, |
295 | + const Widelands::NodeAndTriangle<>& center, |
296 | + EditorInteractive& parent, |
297 | + EditorActionArgs* args, |
298 | + Widelands::Map* map) override; |
299 | + |
300 | + int32_t handle_undo_impl(const Widelands::World& world, |
301 | + const Widelands::NodeAndTriangle<>& center, |
302 | + EditorInteractive& parent, |
303 | + EditorActionArgs* args, |
304 | + Widelands::Map* map) override; |
305 | + |
306 | + EditorActionArgs format_args_impl(EditorInteractive& parent) override; |
307 | + |
308 | + const Image* get_sel_impl() const override { |
309 | + return g_gr->images().get("images/wui/editor/fsel_editor_resize.png"); |
310 | + } |
311 | + |
312 | + bool has_size_one() const override { |
313 | + return true; |
314 | + } |
315 | + |
316 | + void set_width(uint32_t w) { |
317 | + width_ = w; |
318 | + } |
319 | + |
320 | + uint32_t get_width() { |
321 | + return width_; |
322 | + } |
323 | + |
324 | + void set_height(uint32_t h) { |
325 | + height_ = h; |
326 | + } |
327 | + |
328 | + uint32_t get_height() { |
329 | + return height_; |
330 | + } |
331 | + |
332 | +private: |
333 | + uint32_t width_; |
334 | + uint32_t height_; |
335 | +}; |
336 | + |
337 | +#endif // end of include guard: WL_EDITOR_TOOLS_RESIZE_TOOL_H |
338 | |
339 | === modified file 'src/editor/ui_menus/main_menu_new_map.cc' |
340 | --- src/editor/ui_menus/main_menu_new_map.cc 2019-02-23 11:00:49 +0000 |
341 | +++ src/editor/ui_menus/main_menu_new_map.cc 2019-04-23 14:01:41 +0000 |
342 | @@ -51,25 +51,19 @@ |
343 | 0, |
344 | box_width_, |
345 | box_width_ / 3, |
346 | - 0, |
347 | - 0, |
348 | - 0, |
349 | - UI::PanelStyle::kWui, |
350 | - _("Width:"), |
351 | - UI::SpinBox::Units::kNone, |
352 | - UI::SpinBox::Type::kValueList), |
353 | + 24, |
354 | + _("Width"), |
355 | + UI::DropdownType::kTextual, |
356 | + UI::PanelStyle::kWui), |
357 | height_(&box_, |
358 | - 0, |
359 | - 0, |
360 | - box_width_, |
361 | - box_width_ / 3, |
362 | - 0, |
363 | - 0, |
364 | - 0, |
365 | - UI::PanelStyle::kWui, |
366 | - _("Height:"), |
367 | - UI::SpinBox::Units::kNone, |
368 | - UI::SpinBox::Type::kValueList), |
369 | + 0, |
370 | + 0, |
371 | + box_width_, |
372 | + box_width_ / 3, |
373 | + 24, |
374 | + _("Height"), |
375 | + UI::DropdownType::kTextual, |
376 | + UI::PanelStyle::kWui), |
377 | list_(&box_, 0, 0, box_width_, 330, UI::PanelStyle::kWui), |
378 | // Buttons |
379 | button_box_(&box_, 0, 0, UI::Box::Horizontal, 0, 0, margin_), |
380 | @@ -89,25 +83,17 @@ |
381 | 0, |
382 | UI::ButtonStyle::kWuiSecondary, |
383 | _("Cancel")) { |
384 | - width_.set_value_list(Widelands::kMapDimensions); |
385 | - height_.set_value_list(Widelands::kMapDimensions); |
386 | - |
387 | - { |
388 | - size_t width_index, height_index; |
389 | - Widelands::Extent const map_extent = parent.egbase().map().extent(); |
390 | - for (width_index = 0; width_index < Widelands::kMapDimensions.size() && |
391 | - Widelands::kMapDimensions[width_index] < map_extent.w; |
392 | - ++width_index) { |
393 | - } |
394 | - width_.set_value(width_index); |
395 | - |
396 | - for (height_index = 0; height_index < Widelands::kMapDimensions.size() && |
397 | - Widelands::kMapDimensions[height_index] < map_extent.h; |
398 | - ++height_index) { |
399 | - } |
400 | - height_.set_value(height_index); |
401 | + |
402 | + for (const int32_t& i : Widelands::kMapDimensions) { |
403 | + width_.add(std::to_string(i), i); |
404 | + height_.add(std::to_string(i), i); |
405 | } |
406 | + width_.select(parent.egbase().map().get_width()); |
407 | + height_.select(parent.egbase().map().get_height()); |
408 | + width_.set_max_items(12); |
409 | + height_.set_max_items(12); |
410 | |
411 | + box_.set_size(100, 20); // Prevent assert failures |
412 | box_.add(&width_); |
413 | box_.add(&height_); |
414 | box_.add_space(margin_); |
415 | @@ -145,8 +131,8 @@ |
416 | parent.cleanup_for_load(); |
417 | |
418 | map->create_empty_map( |
419 | - egbase.world(), width_.get_value() > 0 ? width_.get_value() : Widelands::kMapDimensions[0], |
420 | - height_.get_value() > 0 ? height_.get_value() : Widelands::kMapDimensions[0], |
421 | + egbase.world(), width_.get_selected() > 0 ? width_.get_selected() : Widelands::kMapDimensions[0], |
422 | + height_.get_selected() > 0 ? height_.get_selected() : Widelands::kMapDimensions[0], |
423 | list_.get_selected(), _("No Name"), |
424 | g_options.pull_section("global").get_string("realname", pgettext("author_name", "Unknown"))); |
425 | |
426 | |
427 | === modified file 'src/editor/ui_menus/main_menu_new_map.h' |
428 | --- src/editor/ui_menus/main_menu_new_map.h 2019-02-23 11:00:49 +0000 |
429 | +++ src/editor/ui_menus/main_menu_new_map.h 2019-04-23 14:01:41 +0000 |
430 | @@ -23,8 +23,8 @@ |
431 | #include "logic/description_maintainer.h" |
432 | #include "ui_basic/box.h" |
433 | #include "ui_basic/button.h" |
434 | +#include "ui_basic/dropdown.h" |
435 | #include "ui_basic/listselect.h" |
436 | -#include "ui_basic/spinbox.h" |
437 | #include "ui_basic/window.h" |
438 | |
439 | class EditorInteractive; |
440 | @@ -46,8 +46,8 @@ |
441 | int32_t margin_; |
442 | int32_t box_width_; |
443 | UI::Box box_; |
444 | - UI::SpinBox width_; |
445 | - UI::SpinBox height_; |
446 | + UI::Dropdown<int32_t> width_; |
447 | + UI::Dropdown<int32_t> height_; |
448 | |
449 | // Terrains list |
450 | UI::Listselect<Widelands::DescriptionIndex> list_; |
451 | |
452 | === modified file 'src/editor/ui_menus/main_menu_random_map.cc' |
453 | --- src/editor/ui_menus/main_menu_random_map.cc 2019-02-23 11:00:49 +0000 |
454 | +++ src/editor/ui_menus/main_menu_random_map.cc 2019-04-23 14:01:41 +0000 |
455 | @@ -59,25 +59,19 @@ |
456 | 0, |
457 | box_width_, |
458 | box_width_ / 3, |
459 | - 0, |
460 | - 0, |
461 | - 0, |
462 | - UI::PanelStyle::kWui, |
463 | - _("Width:"), |
464 | - UI::SpinBox::Units::kNone, |
465 | - UI::SpinBox::Type::kValueList), |
466 | + 24, |
467 | + _("Width"), |
468 | + UI::DropdownType::kTextual, |
469 | + UI::PanelStyle::kWui), |
470 | height_(&box_, |
471 | - 0, |
472 | - 0, |
473 | - box_width_, |
474 | - box_width_ / 3, |
475 | - 0, |
476 | - 0, |
477 | - 0, |
478 | - UI::PanelStyle::kWui, |
479 | - _("Height:"), |
480 | - UI::SpinBox::Units::kNone, |
481 | - UI::SpinBox::Type::kValueList), |
482 | + 0, |
483 | + 0, |
484 | + box_width_, |
485 | + box_width_ / 3, |
486 | + 24, |
487 | + _("Height"), |
488 | + UI::DropdownType::kTextual, |
489 | + UI::PanelStyle::kWui), |
490 | max_players_(2), |
491 | players_(&box_, |
492 | 0, |
493 | @@ -227,23 +221,21 @@ |
494 | |
495 | // ---------- Width + Height ---------- |
496 | |
497 | - width_.set_value_list(Widelands::kMapDimensions); |
498 | - height_.set_value_list(Widelands::kMapDimensions); |
499 | - { |
500 | - Widelands::Extent const map_extent = parent.egbase().map().extent(); |
501 | - width_.set_value(find_dimension_index(map_extent.w)); |
502 | - height_.set_value(find_dimension_index(map_extent.h)); |
503 | + for (const int32_t& i : Widelands::kMapDimensions) { |
504 | + width_.add(std::to_string(i), i); |
505 | + height_.add(std::to_string(i), i); |
506 | } |
507 | - |
508 | - width_.get_buttons()[0]->sigclicked.connect( |
509 | - boost::bind(&MainMenuNewRandomMap::button_clicked, this, ButtonId::kMapSize)); |
510 | - width_.get_buttons()[1]->sigclicked.connect( |
511 | - boost::bind(&MainMenuNewRandomMap::button_clicked, this, ButtonId::kMapSize)); |
512 | - height_.get_buttons()[0]->sigclicked.connect( |
513 | - boost::bind(&MainMenuNewRandomMap::button_clicked, this, ButtonId::kMapSize)); |
514 | - height_.get_buttons()[1]->sigclicked.connect( |
515 | - boost::bind(&MainMenuNewRandomMap::button_clicked, this, ButtonId::kMapSize)); |
516 | - |
517 | + width_.select(parent.egbase().map().get_width()); |
518 | + height_.select(parent.egbase().map().get_height()); |
519 | + width_.set_max_items(12); |
520 | + height_.set_max_items(12); |
521 | + |
522 | + width_.selected.connect( |
523 | + boost::bind(&MainMenuNewRandomMap::button_clicked, this, ButtonId::kMapSize)); |
524 | + height_.selected.connect( |
525 | + boost::bind(&MainMenuNewRandomMap::button_clicked, this, ButtonId::kMapSize)); |
526 | + |
527 | + box_.set_size(100, 20); // Prevent assert failures |
528 | box_.add(&width_); |
529 | box_.add(&height_); |
530 | box_height += margin_ + width_.get_h(); |
531 | @@ -397,6 +389,14 @@ |
532 | center_to_parent(); |
533 | } |
534 | |
535 | +// Helper function for setting the highest number of allowed players dependent on the map size |
536 | +static size_t find_dimension_index(int32_t value) { |
537 | + size_t result = 0; |
538 | + for (; result < Widelands::kMapDimensions.size() && Widelands::kMapDimensions[result] < value; |
539 | + ++result) { |
540 | + } |
541 | + return result; |
542 | +} |
543 | /** |
544 | * Called, when button get clicked |
545 | */ |
546 | @@ -407,7 +407,7 @@ |
547 | // Restrict maximum players according to map size, but allow at least 2 players. |
548 | max_players_ = std::min( |
549 | static_cast<size_t>(kMaxMapgenPlayers), |
550 | - (find_dimension_index(width_.get_value()) + find_dimension_index(height_.get_value())) / |
551 | + (find_dimension_index(width_.get_selected()) + find_dimension_index(height_.get_selected())) / |
552 | 2 + |
553 | 2); |
554 | players_.set_interval(1, max_players_); |
555 | @@ -443,7 +443,7 @@ |
556 | // Make sure that all conditions are met |
557 | max_players_ = std::min( |
558 | static_cast<size_t>(kMaxMapgenPlayers), |
559 | - (find_dimension_index(width_.get_value()) + find_dimension_index(height_.get_value())) / |
560 | + (find_dimension_index(width_.get_selected()) + find_dimension_index(height_.get_selected())) / |
561 | 2 + |
562 | 2); |
563 | players_.set_interval(1, max_players_); |
564 | @@ -604,8 +604,8 @@ |
565 | sstrm << map_info.mapNumber; |
566 | map_number_edit_.set_text(sstrm.str()); |
567 | |
568 | - width_.set_value(find_dimension_index(map_info.w)); |
569 | - height_.set_value(find_dimension_index(map_info.h)); |
570 | + width_.select(map_info.w); |
571 | + height_.select(map_info.h); |
572 | |
573 | players_.set_interval(1, map_info.numPlayers); // hack to make sure we can set the value |
574 | players_.set_value(map_info.numPlayers); |
575 | @@ -658,8 +658,8 @@ |
576 | } |
577 | |
578 | void MainMenuNewRandomMap::set_map_info(Widelands::UniqueRandomMapInfo& map_info) const { |
579 | - map_info.w = width_.get_value() > 0 ? width_.get_value() : Widelands::kMapDimensions[0]; |
580 | - map_info.h = height_.get_value() > 0 ? height_.get_value() : Widelands::kMapDimensions[0]; |
581 | + map_info.w = width_.get_selected() > 0 ? width_.get_selected() : Widelands::kMapDimensions[0]; |
582 | + map_info.h = height_.get_selected() > 0 ? height_.get_selected() : Widelands::kMapDimensions[0]; |
583 | map_info.waterRatio = static_cast<double>(waterval_) / 100.0; |
584 | map_info.landRatio = static_cast<double>(landval_) / 100.0; |
585 | map_info.wastelandRatio = static_cast<double>(wastelandval_) / 100.0; |
586 | @@ -671,10 +671,3 @@ |
587 | map_info.world_name = world_descriptions_[current_world_].name; |
588 | } |
589 | |
590 | -size_t MainMenuNewRandomMap::find_dimension_index(int32_t value) { |
591 | - size_t result = 0; |
592 | - for (; result < Widelands::kMapDimensions.size() && Widelands::kMapDimensions[result] < value; |
593 | - ++result) { |
594 | - } |
595 | - return result; |
596 | -} |
597 | |
598 | === modified file 'src/editor/ui_menus/main_menu_random_map.h' |
599 | --- src/editor/ui_menus/main_menu_random_map.h 2019-02-23 11:00:49 +0000 |
600 | +++ src/editor/ui_menus/main_menu_random_map.h 2019-04-23 14:01:41 +0000 |
601 | @@ -25,6 +25,7 @@ |
602 | #include "base/macros.h" |
603 | #include "ui_basic/box.h" |
604 | #include "ui_basic/checkbox.h" |
605 | +#include "ui_basic/dropdown.h" |
606 | #include "ui_basic/editbox.h" |
607 | #include "ui_basic/spinbox.h" |
608 | #include "ui_basic/textarea.h" |
609 | @@ -81,9 +82,6 @@ |
610 | |
611 | void set_map_info(Widelands::UniqueRandomMapInfo& map_info) const; |
612 | |
613 | - // Helper function to find a map dimension in the global list of available dimensions. |
614 | - size_t find_dimension_index(int32_t value); |
615 | - |
616 | // UI elements |
617 | int32_t margin_; |
618 | int32_t box_width_; |
619 | @@ -91,8 +89,8 @@ |
620 | UI::Box box_; |
621 | |
622 | // Size |
623 | - UI::SpinBox width_; |
624 | - UI::SpinBox height_; |
625 | + UI::Dropdown<int32_t> width_; |
626 | + UI::Dropdown<int32_t> height_; |
627 | |
628 | uint8_t max_players_; |
629 | UI::SpinBox players_; |
630 | |
631 | === modified file 'src/editor/ui_menus/tool_menu.cc' |
632 | --- src/editor/ui_menus/tool_menu.cc 2019-04-09 16:43:49 +0000 |
633 | +++ src/editor/ui_menus/tool_menu.cc 2019-04-23 14:01:41 +0000 |
634 | @@ -36,6 +36,7 @@ |
635 | #include "editor/ui_menus/tool_noise_height_options_menu.h" |
636 | #include "editor/ui_menus/tool_place_critter_options_menu.h" |
637 | #include "editor/ui_menus/tool_place_immovable_options_menu.h" |
638 | +#include "editor/ui_menus/tool_resize_options_menu.h" |
639 | #include "editor/ui_menus/tool_set_terrain_options_menu.h" |
640 | #include "graphic/graphic.h" |
641 | #include "ui_basic/radiobutton.h" |
642 | @@ -50,7 +51,7 @@ |
643 | int32_t const width = 34; |
644 | int32_t const height = 34; |
645 | |
646 | - int32_t const num_tools = 8; |
647 | + int32_t const num_tools = 9; |
648 | #define ADD_BUTTON(pic, tooltip) \ |
649 | radioselect_.add_button( \ |
650 | this, pos, g_gr->images().get("images/wui/editor/editor_menu_tool_" pic ".png"), tooltip); \ |
651 | @@ -64,25 +65,29 @@ |
652 | ADD_BUTTON("change_resources", _("Resources")) |
653 | ADD_BUTTON("set_port_space", _("Set port space")) |
654 | ADD_BUTTON("set_origin", _("Set the position that will have the coordinates (0, 0). This will " |
655 | - "be the top-left corner of a generated minimap.")) |
656 | + "be the top-left corner of a generated minimap.")); |
657 | + ADD_BUTTON("resize", _("Change the map’s size")); |
658 | |
659 | set_inner_size(offs.x + (width + spacing) * num_tools, offs.y + (height + spacing)); |
660 | |
661 | { |
662 | - const EditorTool& current = parent.tools()->current(); |
663 | - radioselect_.set_state(¤t == &parent.tools()->noise_height ? |
664 | + const EditorTool* current = &parent.tools()->current(); |
665 | + radioselect_.set_state(current == &parent.tools()->noise_height ? |
666 | 1 : |
667 | - ¤t == &parent.tools()->set_terrain ? |
668 | + current == &parent.tools()->set_terrain ? |
669 | 2 : |
670 | - ¤t == &parent.tools()->place_immovable ? |
671 | + current == &parent.tools()->place_immovable ? |
672 | 3 : |
673 | - ¤t == &parent.tools()->place_critter ? |
674 | + current == &parent.tools()->place_critter ? |
675 | 4 : |
676 | - ¤t == &parent.tools()->increase_resources ? |
677 | + current == &parent.tools()->increase_resources ? |
678 | 5 : |
679 | - ¤t == &parent.tools()->set_port_space ? |
680 | + current == &parent.tools()->set_port_space ? |
681 | 6 : |
682 | - ¤t == &parent.tools()->set_origin ? 7 : 0); |
683 | + current == &parent.tools()->set_origin ? |
684 | + 7 : |
685 | + current == &parent.tools()->resize ? |
686 | + 8 : 0); |
687 | } |
688 | |
689 | radioselect_.changed.connect(boost::bind(&EditorToolMenu::changed_to, this)); |
690 | @@ -135,6 +140,10 @@ |
691 | current_tool_pointer = &parent.tools()->set_origin; |
692 | current_registry_pointer = nullptr; // no need for a window |
693 | break; |
694 | + case 8: |
695 | + current_tool_pointer = &parent.tools()->resize; |
696 | + current_registry_pointer = &parent.resizemenu_; |
697 | + break; |
698 | default: |
699 | NEVER_HERE(); |
700 | } |
701 | @@ -174,6 +183,10 @@ |
702 | new EditorToolChangeResourcesOptionsMenu( |
703 | parent, parent.tools()->increase_resources, *current_registry_pointer); |
704 | break; |
705 | + case 8: |
706 | + new EditorToolResizeOptionsMenu( |
707 | + parent, parent.tools()->resize, *current_registry_pointer); |
708 | + break; |
709 | default: |
710 | NEVER_HERE(); |
711 | } |
712 | |
713 | === added file 'src/editor/ui_menus/tool_resize_options_menu.cc' |
714 | --- src/editor/ui_menus/tool_resize_options_menu.cc 1970-01-01 00:00:00 +0000 |
715 | +++ src/editor/ui_menus/tool_resize_options_menu.cc 2019-04-23 14:01:41 +0000 |
716 | @@ -0,0 +1,108 @@ |
717 | +/* |
718 | + * Copyright (C) 2002-2019 by the Widelands Development Team |
719 | + * |
720 | + * This program is free software; you can redistribute it and/or |
721 | + * modify it under the terms of the GNU General Public License |
722 | + * as published by the Free Software Foundation; either version 2 |
723 | + * of the License, or (at your option) any later version. |
724 | + * |
725 | + * This program is distributed in the hope that it will be useful, |
726 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
727 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
728 | + * GNU General Public License for more details. |
729 | + * |
730 | + * You should have received a copy of the GNU General Public License |
731 | + * along with this program; if not, write to the Free Software |
732 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
733 | + * |
734 | + */ |
735 | + |
736 | +#include "editor/ui_menus/tool_resize_options_menu.h" |
737 | + |
738 | +#include <cstdio> |
739 | +#include <string> |
740 | + |
741 | +#include "base/i18n.h" |
742 | +#include "base/wexception.h" |
743 | +#include "editor/editorinteractive.h" |
744 | +#include "editor/tools/resize_tool.h" |
745 | +#include "graphic/graphic.h" |
746 | +#include "logic/map.h" |
747 | + |
748 | +inline EditorInteractive& EditorToolResizeOptionsMenu::eia() { |
749 | + return dynamic_cast<EditorInteractive&>(*get_parent()); |
750 | +} |
751 | + |
752 | +EditorToolResizeOptionsMenu::EditorToolResizeOptionsMenu( |
753 | + EditorInteractive& parent, |
754 | + EditorResizeTool& resize_tool, |
755 | + UI::UniqueWindow::Registry& registry) |
756 | + : EditorToolOptionsMenu(parent, registry, 260, 200, _("Resize")), |
757 | + resize_tool_(resize_tool), |
758 | + box_(this, hmargin(), vmargin(), UI::Box::Vertical, 0, 0, vspacing()), |
759 | + new_width_(&box_, |
760 | + 0, |
761 | + 0, |
762 | + get_inner_w() - 2 * hmargin(), |
763 | + 200, |
764 | + 24, |
765 | + _("New width"), |
766 | + UI::DropdownType::kTextual, |
767 | + UI::PanelStyle::kWui), |
768 | + new_height_(&box_, |
769 | + 0, |
770 | + 0, |
771 | + get_inner_w() - 2 * hmargin(), |
772 | + 200, |
773 | + 24, |
774 | + _("New height"), |
775 | + UI::DropdownType::kTextual, |
776 | + UI::PanelStyle::kWui), |
777 | + text_area_(&box_, |
778 | + 0, |
779 | + 0, |
780 | + get_inner_w() - 2 * hmargin(), |
781 | + 48, |
782 | + UI::PanelStyle::kWui, |
783 | + _("Select the new map size, then click the map to split it at the desired location."), |
784 | + UI::Align::kCenter, |
785 | + UI::MultilineTextarea::ScrollMode::kNoScrolling) { |
786 | + |
787 | + for (const int32_t& i : Widelands::kMapDimensions) { |
788 | + new_width_.add(std::to_string(i), i); |
789 | + new_height_.add(std::to_string(i), i); |
790 | + } |
791 | + new_width_.select(parent.egbase().map().get_width()); |
792 | + new_height_.select(parent.egbase().map().get_height()); |
793 | + new_width_.set_max_items(8); |
794 | + new_height_.set_max_items(8); |
795 | + |
796 | + new_width_.selected.connect( |
797 | + boost::bind(&EditorToolResizeOptionsMenu::update_width, boost::ref(*this))); |
798 | + new_height_.selected.connect( |
799 | + boost::bind(&EditorToolResizeOptionsMenu::update_height, boost::ref(*this))); |
800 | + |
801 | + box_.add(&text_area_); |
802 | + box_.set_size(100, 20); // Prevent assert failures |
803 | + box_.add(&new_width_, UI::Box::Resizing::kFullSize); |
804 | + box_.add(&new_height_, UI::Box::Resizing::kFullSize); |
805 | + |
806 | + box_.set_size(get_inner_w() - 2 * hmargin(), |
807 | + new_width_.get_h() + new_height_.get_h() + text_area_.get_h() + 2 * vspacing()); |
808 | + set_inner_size(get_inner_w(), box_.get_h() + 1 * vmargin()); |
809 | +} |
810 | + |
811 | +void EditorToolResizeOptionsMenu::update_width() { |
812 | + int32_t w = new_width_.get_selected(); |
813 | + assert(w > 0); |
814 | + resize_tool_.set_width(w); |
815 | + select_correct_tool(); |
816 | +} |
817 | + |
818 | +void EditorToolResizeOptionsMenu::update_height() { |
819 | + int32_t h = new_height_.get_selected(); |
820 | + assert(h > 0); |
821 | + resize_tool_.set_height(h); |
822 | + select_correct_tool(); |
823 | +} |
824 | + |
825 | |
826 | === added file 'src/editor/ui_menus/tool_resize_options_menu.h' |
827 | --- src/editor/ui_menus/tool_resize_options_menu.h 1970-01-01 00:00:00 +0000 |
828 | +++ src/editor/ui_menus/tool_resize_options_menu.h 2019-04-23 14:01:41 +0000 |
829 | @@ -0,0 +1,48 @@ |
830 | +/* |
831 | + * Copyright (C) 2002-2019 by the Widelands Development Team |
832 | + * |
833 | + * This program is free software; you can redistribute it and/or |
834 | + * modify it under the terms of the GNU General Public License |
835 | + * as published by the Free Software Foundation; either version 2 |
836 | + * of the License, or (at your option) any later version. |
837 | + * |
838 | + * This program is distributed in the hope that it will be useful, |
839 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
840 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
841 | + * GNU General Public License for more details. |
842 | + * |
843 | + * You should have received a copy of the GNU General Public License |
844 | + * along with this program; if not, write to the Free Software |
845 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
846 | + * |
847 | + */ |
848 | + |
849 | +#ifndef WL_EDITOR_UI_MENUS_TOOL_RESIZE_OPTIONS_MENU_H |
850 | +#define WL_EDITOR_UI_MENUS_TOOL_RESIZE_OPTIONS_MENU_H |
851 | + |
852 | +#include "editor/ui_menus/tool_options_menu.h" |
853 | +#include "ui_basic/box.h" |
854 | +#include "ui_basic/dropdown.h" |
855 | +#include "ui_basic/multilinetextarea.h" |
856 | + |
857 | +class EditorInteractive; |
858 | +struct EditorResizeTool; |
859 | + |
860 | +struct EditorToolResizeOptionsMenu : public EditorToolOptionsMenu { |
861 | + EditorToolResizeOptionsMenu(EditorInteractive&, |
862 | + EditorResizeTool&, |
863 | + UI::UniqueWindow::Registry&); |
864 | + |
865 | +private: |
866 | + EditorInteractive& eia(); |
867 | + void update_width(); |
868 | + void update_height(); |
869 | + |
870 | + EditorResizeTool& resize_tool_; |
871 | + UI::Box box_; |
872 | + UI::Dropdown<int32_t> new_width_; |
873 | + UI::Dropdown<int32_t> new_height_; |
874 | + UI::MultilineTextarea text_area_; |
875 | +}; |
876 | + |
877 | +#endif // end of include guard: WL_EDITOR_UI_MENUS_TOOL_RESIZE_OPTIONS_MENU_H |
878 | |
879 | === modified file 'src/logic/map.cc' |
880 | --- src/logic/map.cc 2019-03-24 13:16:11 +0000 |
881 | +++ src/logic/map.cc 2019-04-23 14:01:41 +0000 |
882 | @@ -54,6 +54,21 @@ |
883 | |
884 | namespace Widelands { |
885 | |
886 | +FieldData::FieldData(const Field& field) |
887 | + : height(field.get_height()), |
888 | + resources(field.get_resources()), |
889 | + resource_amount(field.get_initial_res_amount()), |
890 | + terrains(field.get_terrains()) { |
891 | + if (const BaseImmovable* imm = field.get_immovable()) { |
892 | + immovable = imm->descr().name(); |
893 | + } else { |
894 | + immovable = ""; |
895 | + } |
896 | + for (Bob* bob = field.get_first_bob(); bob; bob = bob->get_next_bob()) { |
897 | + bobs.push_back(bob->descr().name()); |
898 | + } |
899 | +} |
900 | + |
901 | /* |
902 | ============================================================================== |
903 | |
904 | @@ -456,6 +471,11 @@ |
905 | filesystem_.reset(nullptr); |
906 | } |
907 | |
908 | +// Made this a separate function to reduce compiler warnings |
909 | +template <typename T = Field> static inline void clear_array(std::unique_ptr<T[]>* array, uint32_t size) { |
910 | + memset(array->get(), 0, sizeof(T) * size); |
911 | +} |
912 | + |
913 | void Map::set_origin(const Coords& new_origin) { |
914 | assert(0 <= new_origin.x); |
915 | assert(new_origin.x < width_); |
916 | @@ -469,7 +489,7 @@ |
917 | } |
918 | |
919 | std::unique_ptr<Field[]> new_field_order(new Field[field_size]); |
920 | - memset(new_field_order.get(), 0, sizeof(Field) * field_size); |
921 | + clear_array<>(&new_field_order, field_size); |
922 | |
923 | // Rearrange The fields |
924 | // NOTE because of the triangle design, we have to take special care of cases |
925 | @@ -524,6 +544,148 @@ |
926 | log("Map origin was shifted by (%d, %d)\n", new_origin.x, new_origin.y); |
927 | } |
928 | |
929 | +/* Helper function for resize(): |
930 | + * Calculates the coords of 'c' after resizing the map from the given old size to the given new size at 'split'. |
931 | + */ |
932 | +static Coords transform_coords(const Coords& c, const Coords& split, |
933 | + int16_t w_new, int16_t h_new, int16_t w_old, int16_t h_old) { |
934 | + const int16_t delta_w = w_new - w_old; |
935 | + const int16_t delta_h = h_new - h_old; |
936 | + if (c.x < split.x && c.y < split.y) { |
937 | + // Nothing to shift |
938 | + Coords result(c); |
939 | + Map::normalize_coords(result, w_new, h_new); |
940 | + return result; |
941 | + } else if ((w_new < w_old && c.x >= split.x && c.x < split.x - delta_w) || |
942 | + (h_new < h_old && c.y >= split.y && c.y < split.y - delta_h)) { |
943 | + // Field removed |
944 | + return Coords::null(); |
945 | + } |
946 | + Coords result(c.x, c.y); |
947 | + if (c.x >= split.x) { |
948 | + result.x += delta_w; |
949 | + } |
950 | + if (c.y >= split.y) { |
951 | + result.y += delta_h; |
952 | + } |
953 | + Map::normalize_coords(result, w_new, h_new); |
954 | + return result; |
955 | +} |
956 | + |
957 | +/* Change the size of the (already initialized) map to 'w'×'h' by inserting/deleting fields south and east of 'split'. |
958 | + * Returns the data of fields that were deleted during resizing. |
959 | + * This function will notify all players of the change in map size, but not of anything else. This is because |
960 | + * the editor may want to do some post-resize cleanup first, and this function is intended to be used only |
961 | + * by the editor anyway. |
962 | + * You should call recalc_whole_map() afterwards to resolve height differences etc. |
963 | + */ |
964 | +std::map<Coords, FieldData> Map::resize(EditorGameBase& egbase, const Coords split, const int32_t w, const int32_t h) { |
965 | + assert(w > 0); |
966 | + assert(h > 0); |
967 | + |
968 | + std::map<Coords, FieldData> deleted; |
969 | + if (w == width_ && h == height_) { |
970 | + return deleted; |
971 | + } |
972 | + |
973 | + const uint32_t field_size = w * h; |
974 | + const uint32_t old_field_size = width_ * height_; |
975 | + |
976 | + std::unique_ptr<Field[]> new_fields(new Field[field_size]); |
977 | + clear_array<>(&new_fields, field_size); |
978 | + |
979 | + // Take care of starting positions and port spaces |
980 | + for (uint8_t i = get_nrplayers(); i > 0; --i) { |
981 | + if (starting_pos_[i - 1]) { |
982 | + starting_pos_[i - 1] = transform_coords(starting_pos_[i - 1], split, w, h, width_, height_); |
983 | + } |
984 | + } |
985 | + |
986 | + PortSpacesSet new_port_spaces; |
987 | + for (Coords it : port_spaces_) { |
988 | + if (Coords c = transform_coords(it, split, w, h, width_, height_)) { |
989 | + new_port_spaces.insert(c); |
990 | + } |
991 | + } |
992 | + port_spaces_ = new_port_spaces; |
993 | + |
994 | + Field::Terrains default_terrains; |
995 | + default_terrains.r = 0; |
996 | + default_terrains.d = 0; |
997 | + |
998 | + std::unique_ptr<bool[]> preserved_coords(new bool[old_field_size]); |
999 | + clear_array<bool>(&preserved_coords, old_field_size); |
1000 | + |
1001 | + const int16_t w_max = w > width_ ? w : width_; |
1002 | + const int16_t h_max = h > height_ ? h : height_; |
1003 | + for (int16_t x = 0; x < w_max; ++x) { |
1004 | + for (int16_t y = 0; y < h_max; ++y) { |
1005 | + Coords c_new = Coords(x, y); |
1006 | + if (x < width_ && y < height_ && !preserved_coords[get_index(c_new, width_)]) { |
1007 | + // Save the data of fields that will be deleted |
1008 | + Field& field = operator[](c_new); |
1009 | + deleted.insert(std::make_pair(c_new, FieldData(field))); |
1010 | + // ...and now we delete stuff that needs removing when the field is destroyed |
1011 | + if (BaseImmovable* imm = field.get_immovable()) { |
1012 | + imm->remove(egbase); |
1013 | + } |
1014 | + while (Bob* bob = field.get_first_bob()) { |
1015 | + bob->remove(egbase); |
1016 | + } |
1017 | + } |
1018 | + if (x < w && y < h) { |
1019 | + if (Coords c_old = transform_coords(c_new, split, width_, height_, w, h)) { |
1020 | + bool& entry = preserved_coords[get_index(c_old, width_)]; |
1021 | + if (!entry) { |
1022 | + // Copy existing field |
1023 | + entry = true; |
1024 | + new_fields[get_index(c_new, w)] = operator[](c_old); |
1025 | + continue; |
1026 | + } |
1027 | + } |
1028 | + // Init new field |
1029 | + Field& field = new_fields[get_index(c_new, w)]; |
1030 | + field.set_height(10); |
1031 | + field.set_terrains(default_terrains); |
1032 | + } |
1033 | + } |
1034 | + } |
1035 | + |
1036 | + // Replace all fields |
1037 | + fields_.reset(new Field[field_size]); |
1038 | + clear_array<>(&fields_, field_size); |
1039 | + for (size_t ind = 0; ind < field_size; ++ind) { |
1040 | + fields_[ind] = new_fields[ind]; |
1041 | + } |
1042 | + log("Resized map from (%d, %d) to (%u, %u) at (%d, %d)\n", width_, height_, w, h, split.x, split.y); |
1043 | + width_ = w; |
1044 | + height_ = h; |
1045 | + |
1046 | + // Inform immovables and bobs about their new position |
1047 | + for (MapIndex idx = 0; idx < field_size; ++idx) { |
1048 | + Field& f = operator[](idx); |
1049 | + if (upcast(Immovable, immovable, f.get_immovable())) { |
1050 | + immovable->position_ = get_fcoords(f); |
1051 | + } |
1052 | + // Ensuring that all bob iterators are changed correctly is a bit hacky, but the more obvious |
1053 | + // solution of doing it like in set_origin() is highly problematic here, or so ASan tells me |
1054 | + std::vector<Bob*> bobs; |
1055 | + for (Bob* bob = f.get_first_bob(); bob; bob = bob->get_next_bob()) { |
1056 | + bobs.push_back(bob); |
1057 | + } |
1058 | + f.bobs = nullptr; |
1059 | + for (Bob* bob : bobs) { |
1060 | + bob->position_.field = nullptr; |
1061 | + bob->linknext_ = nullptr; |
1062 | + bob->linkpprev_ = nullptr; |
1063 | + bob->set_position(egbase, get_fcoords(f)); |
1064 | + } |
1065 | + } |
1066 | + |
1067 | + egbase.allocate_player_maps(); |
1068 | + return deleted; |
1069 | +} |
1070 | + |
1071 | /* |
1072 | =============== |
1073 | Set the size of the map. This should only happen once during initial load. |
1074 | @@ -535,10 +697,12 @@ |
1075 | width_ = w; |
1076 | height_ = h; |
1077 | |
1078 | - fields_.reset(new Field[w * h]); |
1079 | - memset(fields_.get(), 0, sizeof(Field) * w * h); |
1080 | - |
1081 | - pathfieldmgr_->set_size(w * h); |
1082 | + const uint32_t field_size = w * h; |
1083 | + |
1084 | + fields_.reset(new Field[field_size]); |
1085 | + clear_array<>(&fields_, field_size); |
1086 | + |
1087 | + pathfieldmgr_->set_size(field_size); |
1088 | } |
1089 | |
1090 | /* |
1091 | |
1092 | === modified file 'src/logic/map.h' |
1093 | --- src/logic/map.h 2019-03-24 13:16:11 +0000 |
1094 | +++ src/logic/map.h 2019-04-23 14:01:41 +0000 |
1095 | @@ -104,6 +104,18 @@ |
1096 | } // make gcc shut up |
1097 | }; |
1098 | |
1099 | +// Helper struct to save certain elemental data of a field without an actual instance of Field |
1100 | +struct FieldData { |
1101 | + FieldData(const Field& f); |
1102 | + |
1103 | + std::string immovable; |
1104 | + std::list<std::string> bobs; |
1105 | + uint8_t height; |
1106 | + DescriptionIndex resources; |
1107 | + uint8_t resource_amount; |
1108 | + Field::Terrains terrains; |
1109 | +}; |
1110 | + |
1111 | /** class Map |
1112 | * |
1113 | * This really identifies a map like it is in the game |
1114 | @@ -327,6 +339,7 @@ |
1115 | Field& operator[](MapIndex) const; |
1116 | Field& operator[](const Coords&) const; |
1117 | FCoords get_fcoords(const Coords&) const; |
1118 | + static void normalize_coords(Coords&, int16_t, int16_t); |
1119 | void normalize_coords(Coords&) const; |
1120 | FCoords get_fcoords(Field&) const; |
1121 | void get_coords(Field& f, Coords& c) const; |
1122 | @@ -498,6 +511,9 @@ |
1123 | // Visible for testing. |
1124 | void set_size(uint32_t w, uint32_t h); |
1125 | |
1126 | + // Change the map size |
1127 | + std::map<Coords, FieldData> resize(EditorGameBase& egbase, const Coords coords, int32_t w, int32_t h); |
1128 | + |
1129 | private: |
1130 | void recalc_border(const FCoords&); |
1131 | void recalc_brightness(const FCoords&); |
1132 | @@ -588,14 +604,22 @@ |
1133 | } |
1134 | |
1135 | inline void Map::normalize_coords(Coords& c) const { |
1136 | - while (c.x < 0) |
1137 | - c.x += width_; |
1138 | - while (c.x >= width_) |
1139 | - c.x -= width_; |
1140 | - while (c.y < 0) |
1141 | - c.y += height_; |
1142 | - while (c.y >= height_) |
1143 | - c.y -= height_; |
1144 | + normalize_coords(c, width_, height_); |
1145 | +} |
1146 | + |
1147 | +inline void Map::normalize_coords(Coords& c, int16_t w, int16_t h) { |
1148 | + while (c.x < 0) { |
1149 | + c.x += w; |
1150 | + } |
1151 | + while (c.x >= w) { |
1152 | + c.x -= w; |
1153 | + } |
1154 | + while (c.y < 0) { |
1155 | + c.y += h; |
1156 | + } |
1157 | + while (c.y >= h) { |
1158 | + c.y -= h; |
1159 | + } |
1160 | } |
1161 | |
1162 | /** |
Continuous integration builds have changed state:
Travis build 4685. State: errored. Details: https:/ /travis- ci.org/ widelands/ widelands/ builds/ 516924316. /ci.appveyor. com/project/ widelands- dev/widelands/ build/_ widelands_ dev_widelands_ editor_ resize_ map-4471.
Appveyor build 4471. State: success. Details: https:/