Map Editor

RD Core / Commit #3

Commit Map Editor

Alex Alex committed 18/10/2026 23:40 main Patch
436 files +250,791 -0
A RD_Map_Editor/source/doodad_brush.cpp +428-0 View file
@@ -0,0 +1,428 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor is free software: you can redistribute it and/or modify
5+// it under the terms of the GNU General Public License as published by
6+// the Free Software Foundation, either version 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor is distributed in the hope that it will be useful,
10+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+// GNU General Public License for more details.
13+//
14+// You should have received a copy of the GNU General Public License
15+// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#include "main.h"
19+#include "gui.h"
20+
21+#include "doodad_brush.h"
22+#include "basemap.h"
23+
24+#include <boost/lexical_cast.hpp>
25+
26+//=============================================================================
27+// Doodad brush
28+
29+DoodadBrush::DoodadBrush() :
30+ look_id(0),
31+ thickness(0),
32+ thickness_ceiling(0),
33+ draggable(false),
34+ on_blocking(false),
35+ one_size(false),
36+ do_new_borders(false),
37+ on_duplicate(false),
38+ clear_mapflags(0),
39+ clear_statflags(0) {
40+ ////
41+}
42+
43+DoodadBrush::~DoodadBrush() {
44+ for (std::vector<AlternativeBlock*>::iterator alt_iter = alternatives.begin(); alt_iter != alternatives.end(); ++alt_iter) {
45+ delete *alt_iter;
46+ }
47+}
48+
49+DoodadBrush::AlternativeBlock::AlternativeBlock() :
50+ composite_chance(0),
51+ single_chance(0) {
52+ ////
53+}
54+
55+DoodadBrush::AlternativeBlock::~AlternativeBlock() {
56+ for (std::vector<CompositeBlock>::iterator composite_iter = composite_items.begin(); composite_iter != composite_items.end(); ++composite_iter) {
57+ CompositeTileList& tv = composite_iter->items;
58+
59+ for (CompositeTileList::iterator compt_iter = tv.begin(); compt_iter != tv.end(); ++compt_iter) {
60+ ItemVector& items = compt_iter->second;
61+ for (ItemVector::iterator iiter = items.begin(); iiter != items.end(); ++iiter) {
62+ delete *iiter;
63+ }
64+ }
65+ }
66+
67+ for (std::vector<SingleBlock>::iterator single_iter = single_items.begin(); single_iter != single_items.end(); ++single_iter) {
68+ delete single_iter->item;
69+ }
70+}
71+
72+bool DoodadBrush::loadAlternative(pugi::xml_node node, wxArrayString& warnings, AlternativeBlock* which) {
73+ AlternativeBlock* alternativeBlock;
74+ if (which) {
75+ alternativeBlock = which;
76+ } else {
77+ alternativeBlock = newd AlternativeBlock();
78+ }
79+
80+ pugi::xml_attribute attribute;
81+ for (pugi::xml_node childNode = node.first_child(); childNode; childNode = childNode.next_sibling()) {
82+ const std::string& childName = as_lower_str(childNode.name());
83+ if (childName == "item") {
84+ if (!(attribute = childNode.attribute("chance"))) {
85+ warnings.push_back("Can't read chance tag of doodad item node.");
86+ continue;
87+ }
88+
89+ Item* item = Item::Create(childNode);
90+ if (!item) {
91+ warnings.push_back("Can't create item from doodad item node.");
92+ continue;
93+ }
94+
95+ ItemType& it = g_items[item->getID()];
96+ if (it.id != 0) {
97+ it.doodad_brush = this;
98+ }
99+
100+ SingleBlock sb;
101+ sb.item = item;
102+ sb.chance = attribute.as_int();
103+
104+ alternativeBlock->single_items.push_back(sb);
105+ alternativeBlock->single_chance += sb.chance;
106+ } else if (childName == "composite") {
107+ if (!(attribute = childNode.attribute("chance"))) {
108+ warnings.push_back("Can't read chance tag of doodad item node.");
109+ continue;
110+ }
111+
112+ alternativeBlock->composite_chance += attribute.as_int();
113+
114+ CompositeBlock cb;
115+ cb.chance = alternativeBlock->composite_chance;
116+
117+ for (pugi::xml_node compositeNode = childNode.first_child(); compositeNode; compositeNode = compositeNode.next_sibling()) {
118+ if (as_lower_str(compositeNode.name()) != "tile") {
119+ continue;
120+ }
121+
122+ if (!(attribute = compositeNode.attribute("x"))) {
123+ warnings.push_back("Couldn't read positionX values of composite tile node.");
124+ continue;
125+ }
126+
127+ int32_t x = attribute.as_int();
128+ if (!(attribute = compositeNode.attribute("y"))) {
129+ warnings.push_back("Couldn't read positionY values of composite tile node.");
130+ continue;
131+ }
132+
133+ int32_t y = attribute.as_int();
134+ int32_t z = compositeNode.attribute("z").as_int();
135+ if (x < -0x7FFF || x > 0x7FFF) {
136+ warnings.push_back("Invalid range of x value on composite tile node.");
137+ continue;
138+ } else if (y < -0x7FFF || y > 0x7FFF) {
139+ warnings.push_back("Invalid range of y value on composite tile node.");
140+ continue;
141+ } else if (z < -0x7 || z > 0x7) {
142+ warnings.push_back("Invalid range of z value on composite tile node.");
143+ continue;
144+ }
145+
146+ ItemVector items;
147+ for (pugi::xml_node itemNode = compositeNode.first_child(); itemNode; itemNode = itemNode.next_sibling()) {
148+ if (as_lower_str(itemNode.name()) != "item") {
149+ continue;
150+ }
151+
152+ Item* item = Item::Create(itemNode);
153+ if (item) {
154+ items.push_back(item);
155+
156+ ItemType& it = g_items[item->getID()];
157+ if (it.id != 0) {
158+ it.doodad_brush = this;
159+ }
160+ }
161+ }
162+
163+ if (!items.empty()) {
164+ cb.items.push_back(std::make_pair(Position(x, y, z), items));
165+ }
166+ }
167+ alternativeBlock->composite_items.push_back(cb);
168+ }
169+ }
170+
171+ if (!which) {
172+ alternatives.push_back(alternativeBlock);
173+ }
174+ return true;
175+}
176+
177+bool DoodadBrush::load(pugi::xml_node node, wxArrayString& warnings) {
178+ pugi::xml_attribute attribute;
179+ if ((attribute = node.attribute("lookid"))) {
180+ look_id = attribute.as_ushort();
181+ }
182+
183+ if ((attribute = node.attribute("server_lookid"))) {
184+ look_id = g_items[attribute.as_ushort()].clientID;
185+ }
186+
187+ if ((attribute = node.attribute("on_blocking"))) {
188+ on_blocking = attribute.as_bool();
189+ }
190+
191+ if ((attribute = node.attribute("on_duplicate"))) {
192+ on_duplicate = attribute.as_bool();
193+ }
194+
195+ if ((attribute = node.attribute("redo_borders")) || (attribute = node.attribute("reborder"))) {
196+ do_new_borders = attribute.as_bool();
197+ }
198+
199+ if ((attribute = node.attribute("one_size"))) {
200+ one_size = attribute.as_bool();
201+ }
202+
203+ if ((attribute = node.attribute("draggable"))) {
204+ draggable = attribute.as_bool();
205+ }
206+
207+ if (node.attribute("remove_optional_border").as_bool()) {
208+ if (!do_new_borders) {
209+ warnings.push_back("remove_optional_border will not work without redo_borders\n");
210+ }
211+ clear_statflags |= TILESTATE_OP_BORDER;
212+ }
213+
214+ const std::string& thicknessString = node.attribute("thickness").as_string();
215+ if (!thicknessString.empty()) {
216+ size_t slash = thicknessString.find('/');
217+ if (slash != std::string::npos) {
218+ thickness = boost::lexical_cast<int32_t>(thicknessString.substr(0, slash));
219+ thickness_ceiling = std::max<int32_t>(thickness, boost::lexical_cast<int32_t>(thicknessString.substr(slash + 1)));
220+ }
221+ }
222+
223+ for (pugi::xml_node childNode = node.first_child(); childNode; childNode = childNode.next_sibling()) {
224+ if (as_lower_str(childNode.name()) != "alternate") {
225+ continue;
226+ }
227+ if (!loadAlternative(childNode, warnings)) {
228+ return false;
229+ }
230+ }
231+ loadAlternative(node, warnings, alternatives.empty() ? nullptr : alternatives.back());
232+ return true;
233+}
234+
235+bool DoodadBrush::AlternativeBlock::ownsItem(uint16_t id) const {
236+ for (std::vector<SingleBlock>::const_iterator single_iter = single_items.begin(); single_iter != single_items.end(); ++single_iter) {
237+ if (single_iter->item->getID() == id) {
238+ return true;
239+ }
240+ }
241+
242+ for (std::vector<CompositeBlock>::const_iterator composite_iter = composite_items.begin(); composite_iter != composite_items.end(); ++composite_iter) {
243+ const CompositeTileList& ctl = composite_iter->items;
244+ for (CompositeTileList::const_iterator comp_iter = ctl.begin(); comp_iter != ctl.end(); ++comp_iter) {
245+ const ItemVector& items = comp_iter->second;
246+
247+ for (ItemVector::const_iterator item_iter = items.begin(), item_end = items.end(); item_iter != item_end; ++item_iter) {
248+ if ((*item_iter)->getID() == id) {
249+ return true;
250+ }
251+ }
252+ }
253+ }
254+ return false;
255+}
256+
257+bool DoodadBrush::ownsItem(Item* item) const {
258+ if (item->getDoodadBrush() == this) {
259+ return true;
260+ }
261+ uint16_t id = item->getID();
262+
263+ for (std::vector<AlternativeBlock*>::const_iterator alt_iter = alternatives.begin(); alt_iter != alternatives.end(); ++alt_iter) {
264+ if ((*alt_iter)->ownsItem(id)) {
265+ return true;
266+ }
267+ }
268+ return false;
269+}
270+
271+void DoodadBrush::undraw(BaseMap* map, Tile* tile) {
272+ // Remove all doodad-related
273+ for (ItemVector::iterator item_iter = tile->items.begin(); item_iter != tile->items.end();) {
274+ Item* item = *item_iter;
275+ if (item->getDoodadBrush() != nullptr) {
276+ if (item->isComplex() && g_settings.getInteger(Config::ERASER_LEAVE_UNIQUE)) {
277+ ++item_iter;
278+ } else if (g_settings.getInteger(Config::DOODAD_BRUSH_ERASE_LIKE)) {
279+ // Only delete items of the same doodad brush
280+ if (ownsItem(item)) {
281+ delete item;
282+ item_iter = tile->items.erase(item_iter);
283+ } else {
284+ ++item_iter;
285+ }
286+ } else {
287+ delete item;
288+ item_iter = tile->items.erase(item_iter);
289+ }
290+ } else {
291+ ++item_iter;
292+ }
293+ }
294+
295+ if (tile->ground && tile->ground->getDoodadBrush() != nullptr) {
296+ if (g_settings.getInteger(Config::DOODAD_BRUSH_ERASE_LIKE)) {
297+ // Only delete items of the same doodad brush
298+ if (ownsItem(tile->ground)) {
299+ delete tile->ground;
300+ tile->ground = nullptr;
301+ }
302+ } else {
303+ delete tile->ground;
304+ tile->ground = nullptr;
305+ }
306+ }
307+}
308+
309+void DoodadBrush::draw(BaseMap* map, Tile* tile, void* parameter) {
310+ int variation = 0;
311+ if (parameter) {
312+ variation = *reinterpret_cast<int*>(parameter);
313+ }
314+
315+ if (alternatives.empty()) {
316+ return;
317+ }
318+
319+ variation %= alternatives.size();
320+ const AlternativeBlock* ab_ptr = alternatives[variation];
321+ ASSERT(ab_ptr);
322+
323+ int roll = random(1, ab_ptr->single_chance);
324+ for (std::vector<SingleBlock>::const_iterator block_iter = ab_ptr->single_items.begin(); block_iter != ab_ptr->single_items.end(); ++block_iter) {
325+ const SingleBlock& sb = *block_iter;
326+ if (roll <= sb.chance) {
327+ // Use this!
328+ Item* new_item = sb.item->deepCopy();
329+ if (new_item && g_gui.IsCurrentActionIDEnabled()) {
330+ new_item->setActionID(g_gui.GetCurrentActionID());
331+ }
332+ tile->addItem(new_item);
333+ break;
334+ }
335+ roll -= sb.chance;
336+ }
337+ if (clear_mapflags || clear_statflags) {
338+ tile->setMapFlags(tile->getMapFlags() & (~clear_mapflags));
339+ tile->setMapFlags(tile->getStatFlags() & (~clear_statflags));
340+ if (clear_mapflags & TILESTATE_ZONE_BRUSH) {
341+ tile->clearZoneId();
342+ }
343+ }
344+}
345+
346+const CompositeTileList& DoodadBrush::getComposite(int variation) const {
347+ static CompositeTileList empty;
348+
349+ if (alternatives.empty()) {
350+ return empty;
351+ }
352+
353+ variation %= alternatives.size();
354+ const AlternativeBlock* ab_ptr = alternatives[variation];
355+ ASSERT(ab_ptr);
356+
357+ int roll = random(1, ab_ptr->composite_chance);
358+ for (std::vector<CompositeBlock>::const_iterator block_iter = ab_ptr->composite_items.begin(); block_iter != ab_ptr->composite_items.end(); ++block_iter) {
359+ const CompositeBlock& cb = *block_iter;
360+ if (roll <= cb.chance) {
361+ return cb.items;
362+ }
363+ }
364+ return empty;
365+}
366+
367+bool DoodadBrush::isEmpty(int variation) const {
368+ if (hasCompositeObjects(variation)) {
369+ return false;
370+ }
371+ if (hasSingleObjects(variation)) {
372+ return false;
373+ }
374+ if (thickness <= 0) {
375+ return false;
376+ }
377+ return true;
378+}
379+
380+int DoodadBrush::getCompositeChance(int ab) const {
381+ if (alternatives.empty()) {
382+ return 0;
383+ }
384+ ab %= alternatives.size();
385+ const AlternativeBlock* ab_ptr = alternatives[ab];
386+ ASSERT(ab_ptr);
387+ return ab_ptr->composite_chance;
388+}
389+
390+int DoodadBrush::getSingleChance(int ab) const {
391+ if (alternatives.empty()) {
392+ return 0;
393+ }
394+ ab %= alternatives.size();
395+ const AlternativeBlock* ab_ptr = alternatives[ab];
396+ ASSERT(ab_ptr);
397+ return ab_ptr->single_chance;
398+}
399+
400+int DoodadBrush::getTotalChance(int ab) const {
401+ if (alternatives.empty()) {
402+ return 0;
403+ }
404+ ab %= alternatives.size();
405+ const AlternativeBlock* ab_ptr = alternatives[ab];
406+ ASSERT(ab_ptr);
407+ return ab_ptr->composite_chance + ab_ptr->single_chance;
408+}
409+
410+bool DoodadBrush::hasSingleObjects(int ab) const {
411+ if (alternatives.empty()) {
412+ return false;
413+ }
414+ ab %= alternatives.size();
415+ AlternativeBlock* ab_ptr = alternatives[ab];
416+ ASSERT(ab_ptr);
417+ return ab_ptr->single_chance > 0;
418+}
419+
420+bool DoodadBrush::hasCompositeObjects(int ab) const {
421+ if (alternatives.empty()) {
422+ return false;
423+ }
424+ ab %= alternatives.size();
425+ AlternativeBlock* ab_ptr = alternatives[ab];
426+ ASSERT(ab_ptr);
427+ return ab_ptr->composite_chance > 0;
428+}
A RD_Map_Editor/source/doodad_brush.h +142-0 View file
@@ -0,0 +1,142 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor is free software: you can redistribute it and/or modify
5+// it under the terms of the GNU General Public License as published by
6+// the Free Software Foundation, either version 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor is distributed in the hope that it will be useful,
10+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+// GNU General Public License for more details.
13+//
14+// You should have received a copy of the GNU General Public License
15+// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_DOODAD_BRUSH_H
19+#define RME_DOODAD_BRUSH_H
20+
21+#include "brush.h"
22+
23+//=============================================================================
24+// Doodadbrush, add doodads!
25+
26+typedef std::vector<std::pair<Position, ItemVector>> CompositeTileList;
27+
28+class DoodadBrush : public Brush {
29+public:
30+ DoodadBrush();
31+ virtual ~DoodadBrush();
32+
33+ bool isDoodad() const {
34+ return true;
35+ }
36+ DoodadBrush* asDoodad() {
37+ return static_cast<DoodadBrush*>(this);
38+ }
39+
40+protected:
41+ struct AlternativeBlock;
42+
43+public:
44+ bool loadAlternative(pugi::xml_node node, wxArrayString& warnings, AlternativeBlock* which = nullptr);
45+ virtual bool load(pugi::xml_node node, wxArrayString& warnings);
46+
47+ virtual bool canDraw(BaseMap* map, const Position& position) const {
48+ return true;
49+ }
50+ virtual void draw(BaseMap* map, Tile* tile, void* parameter);
51+ const CompositeTileList& getComposite(int variation) const;
52+ virtual void undraw(BaseMap* map, Tile* tile);
53+
54+ bool isEmpty(int variation) const;
55+
56+ int getThickness() const {
57+ return thickness;
58+ }
59+ int getThicknessCeiling() const {
60+ return thickness_ceiling;
61+ }
62+
63+ int getCompositeChance(int variation) const;
64+ int getSingleChance(int variation) const;
65+ int getTotalChance(int variation) const;
66+
67+ bool hasSingleObjects(int variation) const;
68+ bool hasCompositeObjects(int variation) const;
69+
70+ bool placeOnBlocking() const {
71+ return on_blocking;
72+ }
73+ bool placeOnDuplicate() const {
74+ return on_duplicate;
75+ }
76+ bool doNewBorders() const {
77+ return do_new_borders;
78+ }
79+ bool ownsItem(Item* item) const;
80+
81+ virtual bool canSmear() const {
82+ return draggable;
83+ }
84+ virtual bool canDrag() const {
85+ return false;
86+ }
87+ virtual bool oneSizeFitsAll() const {
88+ return one_size;
89+ }
90+ virtual int getLookID() const {
91+ return look_id;
92+ }
93+ virtual int getMaxVariation() const {
94+ return alternatives.size();
95+ }
96+ virtual std::string getName() const {
97+ return name;
98+ }
99+ virtual void setName(const std::string& newName) {
100+ name = newName;
101+ }
102+
103+protected:
104+ std::string name;
105+ uint16_t look_id;
106+
107+ int thickness;
108+ int thickness_ceiling;
109+
110+ bool draggable;
111+ bool on_blocking;
112+ bool one_size;
113+ bool do_new_borders;
114+ bool on_duplicate;
115+ uint16_t clear_mapflags;
116+ uint16_t clear_statflags;
117+
118+ struct SingleBlock {
119+ int chance;
120+ Item* item;
121+ };
122+
123+ struct CompositeBlock {
124+ int chance;
125+ CompositeTileList items;
126+ };
127+
128+ struct AlternativeBlock {
129+ AlternativeBlock();
130+ ~AlternativeBlock();
131+ bool ownsItem(uint16_t id) const;
132+ std::vector<SingleBlock> single_items;
133+ std::vector<CompositeBlock> composite_items;
134+
135+ int composite_chance; // Total chance of a composite
136+ int single_chance; // Total chance of a single object
137+ };
138+
139+ std::vector<AlternativeBlock*> alternatives;
140+};
141+
142+#endif
A RD_Map_Editor/source/editor.h +181-0 View file
@@ -0,0 +1,181 @@
1+//////////////////////////////////////////////////////////////////////
2+// This file is part of Remere's Map Editor
3+//////////////////////////////////////////////////////////////////////
4+// Remere's Map Editor is free software: you can redistribute it and/or modify
5+// it under the terms of the GNU General Public License as published by
6+// the Free Software Foundation, either version 3 of the License, or
7+// (at your option) any later version.
8+//
9+// Remere's Map Editor is distributed in the hope that it will be useful,
10+// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+// GNU General Public License for more details.
13+//
14+// You should have received a copy of the GNU General Public License
15+// along with this program. If not, see <http://www.gnu.org/licenses/>.
16+//////////////////////////////////////////////////////////////////////
17+
18+#ifndef RME_EDITOR_H
19+#define RME_EDITOR_H
20+
21+#include "item.h"
22+#include "tile.h"
23+#include "iomap.h"
24+#include "map.h"
25+
26+#include "action.h"
27+#include "selection.h"
28+#include "minimap_window.h"
29+
30+class BaseMap;
31+class CopyBuffer;
32+class LiveClient;
33+class LiveServer;
34+class LiveSocket;
35+
36+class Editor {
37+public:
38+ Editor(CopyBuffer& copybuffer, LiveClient* client);
39+ Editor(CopyBuffer& copybuffer, const FileName& fn);
40+ Editor(CopyBuffer& copybuffer);
41+ ~Editor();
42+
43+protected:
44+ // Live Server
45+ LiveServer* live_server;
46+ LiveClient* live_client;
47+
48+public:
49+ // Public members
50+ ActionQueue* actionQueue;
51+ Selection selection;
52+ CopyBuffer& copybuffer;
53+ GroundBrush* replace_brush;
54+ Map map; // The map that is being edited
55+
56+public: // Functions
57+ // Live Server handling
58+ LiveClient* GetLiveClient() const;
59+ LiveServer* GetLiveServer() const;
60+ LiveSocket& GetLive() const;
61+ bool CanEdit() const {
62+ return true;
63+ }
64+ bool IsLocal() const;
65+ bool IsLive() const;
66+ bool IsLiveServer() const;
67+ bool IsLiveClient() const;
68+
69+ // Server side
70+ LiveServer* StartLiveServer();
71+ void CloseLiveServer();
72+ void BroadcastNodes(DirtyList& dirty_list);
73+
74+ // Client side
75+ void QueryNode(int ndx, int ndy, bool underground);
76+ void SendNodeRequests();
77+
78+ // Map handling
79+ void saveMap(FileName filename, bool showdialog); // "" means default filename
80+
81+ Map& getMap() noexcept {
82+ return map;
83+ }
84+ const Map& getMap() const noexcept {
85+ return map;
86+ }
87+
88+ uint16_t getMapWidth() const {
89+ return map.width;
90+ }
91+ uint16_t getMapHeight() const {
92+ return map.height;
93+ }
94+
95+ wxString getLoaderError() const {
96+ return map.getError();
97+ }
98+ bool importMap(FileName filename, int import_x_offset, int import_y_offset, ImportType house_import_type, ImportType spawn_import_type);
99+ bool importMiniMap(FileName filename, int import, int import_x_offset, int import_y_offset, int import_z_offset);
100+ bool exportMiniMap(FileName filename, int floor /*= GROUND_LAYER*/, bool displaydialog);
101+ bool exportSelectionAsMiniMap(FileName directory, wxString fileName);
102+
103+ // Adds an action to the action queue (this allows the user to undo the action)
104+ // Invalidates the action pointer
105+ void addBatch(BatchAction* action, int stacking_delay = 0);
106+ void addAction(Action* action, int stacking_delay = 0);
107+
108+
109+ // Selection
110+ bool hasSelection() const {
111+ return selection.size() != 0;
112+ }
113+ // Some simple actions that work on the map (these will work through the undo queue)
114+ // Moves the selected area by the offset
115+ void moveSelection(Position offset);
116+ // Deletes all selected items
117+ void destroySelection();
118+ // Borderizes the selected region
119+ void borderizeSelection();
120+ // Randomizes the ground in the selected region
121+ void randomizeSelection();
122+
123+ // Same as above although it applies to the entire map
124+ // action queue is flushed when these functions are called
125+ // showdialog is whether a progress bar should be shown
126+ void borderizeMap(bool showdialog);
127+ void randomizeMap(bool showdialog);
128+ void clearInvalidHouseTiles(bool showdialog);
129+ void clearModifiedTileState(bool showdialog);
130+
131+ // Draw using the current brush to the target position
132+ // alt is whether the ALT key is pressed
133+ void draw(const Position& offset, bool alt);
134+ void undraw(const Position& offset, bool alt);
135+ void draw(const PositionVector& posvec, bool alt);
136+ void draw(const PositionVector& todraw, PositionVector& toborder, bool alt);
137+ void undraw(const PositionVector& posvec, bool alt);
138+ void undraw(const PositionVector& todraw, PositionVector& toborder, bool alt);
139+
140+ // Minimap update helpers
141+ void updateMinimap(const Position& pos);
142+ void updateMinimap(const PositionVector& positions);
143+ void updateMinimapTile(Tile* tile);
144+
145+ // Ground validation methods
146+ uint32_t validateGrounds(bool validateStack, bool generateEmpty, bool removeDuplicates);
147+ uint32_t validateGroundStacks();
148+ uint32_t generateEmptySurroundedGrounds();
149+ uint32_t removeDuplicateGrounds();
150+
151+protected:
152+ void drawInternal(const Position offset, bool alt, bool dodraw);
153+ void drawInternal(const PositionVector& posvec, bool alt, bool dodraw);
154+ void drawInternal(const PositionVector& todraw, PositionVector& toborder, bool alt, bool dodraw);
155+
156+ Editor(const Editor&);
157+ Editor& operator=(const Editor&);
158+};
159+
160+inline void Editor::draw(const Position& offset, bool alt) {
161+ drawInternal(offset, alt, true);
162+}
163+inline void Editor::undraw(const Position& offset, bool alt) {
164+ drawInternal(offset, alt, false);
165+}
166+inline void Editor::draw(const PositionVector& posvec, bool alt) {
167+ drawInternal(posvec, alt, true);
168+}
169+inline void Editor::draw(const PositionVector& todraw, PositionVector& toborder, bool alt) {
170+ drawInternal(todraw, toborder, alt, true);
171+}
172+inline void Editor::undraw(const PositionVector& posvec, bool alt) {
173+ drawInternal(posvec, alt, false);
174+}
175+inline void Editor::undraw(const PositionVector& todraw, PositionVector& toborder, bool alt) {
176+ drawInternal(todraw, toborder, alt, false);
177+}
178+
179+
180+
181+#endif
Top