Merge lp:~widelands-dev/widelands/editor-resize-map into lp:widelands

Proposed by Benedikt Straub
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
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.

To post a comment you must log in.
Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4685. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/516924316.
Appveyor build 4471. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_resize_map-4471.

Revision history for this message
GunChleoc (gunchleoc) wrote :

First round of code review done. Not tested yet.

Revision history for this message
Benedikt Straub (nordfriese) wrote :

Thanks for the review, implemented your suggestions

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4695. State: passed. Details: https://travis-ci.org/widelands/widelands/builds/517211510.
Appveyor build 4481. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_resize_map-4481.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Changes LGTM :)

Not tested yet.

review: Approve
Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4708. State: failed. Details: https://travis-ci.org/widelands/widelands/builds/518246751.
Appveyor build 4494. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_resize_map-4494.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Changes look good. I have done some testing with a few random maps - no issues :)

review: Approve
Revision history for this message
GunChleoc (gunchleoc) wrote :

Transient failure on Travis

@bunnybot merge force

Revision history for this message
bunnybot (widelandsofficial) wrote :

Error merging this proposal:

Output:
stdout:

stderr:
+N data/images/wui/editor/editor_menu_tool_resize.png
+N data/images/wui/editor/fsel_editor_resize.png
+N src/editor/tools/resize_tool.cc
+N src/editor/tools/resize_tool.h
+N src/editor/ui_menus/tool_resize_options_menu.cc
+N src/editor/ui_menus/tool_resize_options_menu.h
 M src/editor/CMakeLists.txt
 M src/editor/editorinteractive.cc
 M src/editor/editorinteractive.h
 M src/editor/tools/action_args.h
 M src/editor/tools/history.cc
 M src/editor/ui_menus/main_menu_new_map.cc
 M src/editor/ui_menus/main_menu_new_map.h
 M src/editor/ui_menus/main_menu_random_map.cc
 M src/editor/ui_menus/main_menu_random_map.h
 M src/editor/ui_menus/tool_menu.cc
 M src/logic/map.cc
 M src/logic/map.h
Text conflict in src/editor/ui_menus/tool_menu.cc
1 conflicts encountered.

Revision history for this message
bunnybot (widelandsofficial) wrote :

Continuous integration builds have changed state:

Travis build 4766. State: errored. Details: https://travis-ci.org/widelands/widelands/builds/523536087.
Appveyor build 4550. State: success. Details: https://ci.appveyor.com/project/widelands-dev/widelands/build/_widelands_dev_widelands_editor_resize_map-4550.

Revision history for this message
GunChleoc (gunchleoc) wrote :

Transient failure on Travis

@bunnybot merge

Revision history for this message
GunChleoc (gunchleoc) wrote :

@bunnybot merge force

Revision history for this message
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://travis-ci.org/widelands/widelands/builds/523536087.

Revision history for this message
GunChleoc (gunchleoc) wrote :

@bunnybot merge force

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'data/images/wui/editor/editor_menu_tool_resize.png'
2Binary 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'
4Binary 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(&current == &parent.tools()->noise_height ?
664+ const EditorTool* current = &parent.tools()->current();
665+ radioselect_.set_state(current == &parent.tools()->noise_height ?
666 1 :
667- &current == &parent.tools()->set_terrain ?
668+ current == &parent.tools()->set_terrain ?
669 2 :
670- &current == &parent.tools()->place_immovable ?
671+ current == &parent.tools()->place_immovable ?
672 3 :
673- &current == &parent.tools()->place_critter ?
674+ current == &parent.tools()->place_critter ?
675 4 :
676- &current == &parent.tools()->increase_resources ?
677+ current == &parent.tools()->increase_resources ?
678 5 :
679- &current == &parent.tools()->set_port_space ?
680+ current == &parent.tools()->set_port_space ?
681 6 :
682- &current == &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 /**

Subscribers

People subscribed via source and target branches

to status/vote changes: