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/templates.h +38-0 View file
@@ -0,0 +1,38 @@
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_MAP_TEMPLATES_H_
19+#define RME_MAP_TEMPLATES_H_
20+
21+#include "common.h"
22+
23+struct ConversionMap {
24+ // Many to Many
25+ typedef std::map<std::vector<uint16_t>, std::vector<uint16_t>> MTM;
26+ // Single to Many
27+ typedef std::map<uint16_t, std::vector<uint16_t>> STM;
28+
29+ MTM mtm;
30+ STM stm;
31+};
32+
33+ConversionMap getReplacementMapFrom800To810();
34+ConversionMap getReplacementMapFrom760To740();
35+ConversionMap getReplacementMapFrom854To854();
36+ConversionMap getReplacementMapClassic();
37+
38+#endif
A RD_Map_Editor/source/threads.h +50-0 View file
@@ -0,0 +1,50 @@
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_THREAD_H_
19+#define RME_THREAD_H_
20+
21+#include "main.h"
22+
23+class Thread : public wxThread {
24+public:
25+ Thread(wxThreadKind);
26+
27+ void Execute(); // Calls "Create" and then "Run"
28+};
29+
30+class JoinableThread : public Thread {
31+public:
32+ JoinableThread() :
33+ Thread(wxTHREAD_JOINABLE) { }
34+};
35+
36+class DetachedThread : public Thread {
37+public:
38+ DetachedThread() :
39+ Thread(wxTHREAD_DETACHED) { }
40+};
41+
42+inline Thread::Thread(wxThreadKind kind) :
43+ wxThread(kind) { }
44+
45+inline void Thread::Execute() {
46+ Create();
47+ Run();
48+}
49+
50+#endif
A RD_Map_Editor/source/tile.h +383-0 View file
@@ -0,0 +1,383 @@
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_TILE_H
19+#define RME_TILE_H
20+
21+#include "position.h"
22+#include "item.h"
23+#include "map_region.h"
24+#include <unordered_set>
25+
26+enum {
27+ TILESTATE_NONE = 0x0000,
28+ TILESTATE_PROTECTIONZONE = 0x0001,
29+ TILESTATE_DEPRECATED = 0x0002, // Reserved
30+ TILESTATE_NOPVP = 0x0004,
31+ TILESTATE_NOLOGOUT = 0x0008,
32+ TILESTATE_PVPZONE = 0x0010,
33+ TILESTATE_REFRESH = 0x0020,
34+ TILESTATE_ZONE_BRUSH = 0x0040,
35+ // Internal
36+ TILESTATE_SELECTED = 0x0001,
37+ TILESTATE_UNIQUE = 0x0002,
38+ TILESTATE_BLOCKING = 0x0004,
39+ TILESTATE_OP_BORDER = 0x0008, // If this is true, gravel will be placed on the tile!
40+ TILESTATE_HAS_TABLE = 0x0010,
41+ TILESTATE_HAS_CARPET = 0x0020,
42+ TILESTATE_MODIFIED = 0x0040,
43+};
44+
45+enum : uint8_t {
46+ INVALID_MINIMAP_COLOR = 0xFF
47+};
48+
49+class Tile {
50+public: // Members
51+ TileLocation* location;
52+ Item* ground;
53+ ItemVector items;
54+ Creature* creature;
55+ Spawn* spawn;
56+ uint32_t house_id; // House id for this tile (pointer not safe)
57+
58+public:
59+ // ALWAYS use this constructor if the Tile is EVER going to be placed on a map
60+ Tile(TileLocation& location);
61+ // Use this when the tile is only used internally by the editor (like in certain brushes)
62+ Tile(int x, int y, int z);
63+
64+ ~Tile();
65+
66+ // Argument is a the map to allocate the tile from
67+ Tile* deepCopy(BaseMap& map);
68+
69+ // The location of the tile
70+ // Stores state that remains between the tile being moved (like house exits)
71+ void setLocation(TileLocation* where) {
72+ location = where;
73+ }
74+ TileLocation* getLocation() {
75+ return location;
76+ }
77+ const TileLocation* getLocation() const {
78+ return location;
79+ }
80+
81+ // Position of the tile
82+ Position getPosition() {
83+ return location->getPosition();
84+ }
85+ const Position getPosition() const {
86+ return location->getPosition();
87+ }
88+ int getX() const {
89+ return location->getPosition().x;
90+ }
91+ int getY() const {
92+ return location->getPosition().y;
93+ }
94+ int getZ() const {
95+ return location->getPosition().z;
96+ }
97+
98+public: // Functions
99+ // Absorb the other tile into this tile
100+ void merge(Tile* other);
101+
102+ // Has tile been modified since the map was loaded/created?
103+ bool isModified() const {
104+ return testFlags(statflags, TILESTATE_MODIFIED);
105+ }
106+ void modify() {
107+ statflags |= TILESTATE_MODIFIED;
108+ }
109+ void unmodify() {
110+ statflags &= ~TILESTATE_MODIFIED;
111+ }
112+
113+ // Get memory footprint size
114+ uint32_t memsize() const;
115+ // Get number of items on the tile
116+ bool empty() const {
117+ return size() == 0;
118+ }
119+ int size() const;
120+
121+ // Blocking?
122+ bool isBlocking() const {
123+ return testFlags(statflags, TILESTATE_BLOCKING);
124+ }
125+
126+ // PZ
127+ bool isPZ() const {
128+ return testFlags(mapflags, TILESTATE_PROTECTIONZONE);
129+ }
130+ void setPZ(bool pz) {
131+ if (pz) {
132+ mapflags |= TILESTATE_PROTECTIONZONE;
133+ } else {
134+ mapflags &= ~TILESTATE_PROTECTIONZONE;
135+ }
136+ }
137+
138+ bool hasProperty(enum ITEMPROPERTY prop) const;
139+
140+ int getIndexOf(Item* item) const;
141+ Item* getTopItem() const; // Returns the topmost item, or nullptr if the tile is empty
142+ Item* getItemAt(int index) const;
143+ void addItem(Item* item);
144+
145+ void select();
146+ void deselect();
147+ // This selects borders too
148+ void selectGround();
149+ void deselectGround();
150+
151+ bool isSelected() const {
152+ return testFlags(statflags, TILESTATE_SELECTED);
153+ }
154+ bool hasUniqueItem() const {
155+ return testFlags(statflags, TILESTATE_UNIQUE);
156+ }
157+
158+ ItemVector popSelectedItems(bool ignoreTileSelected = false);
159+ ItemVector getSelectedItems(bool unzoomed = false);
160+ Item* getTopSelectedItem();
161+
162+ // Refresh internal flags (such as selected etc.)
163+ void update();
164+
165+ uint8_t getMiniMapColor() const;
166+
167+ // Does this tile have ground?
168+ bool hasGround() const {
169+ return ground != nullptr;
170+ }
171+ bool hasBorders() const {
172+ return items.size() && items[0]->isBorder();
173+ }
174+
175+ // Get the border brush of this tile
176+ GroundBrush* getGroundBrush() const;
177+
178+ // Remove all borders (for autoborder)
179+ void cleanBorders();
180+
181+ // Add a border item (added at the bottom of all items)
182+ void addBorderItem(Item* item);
183+
184+ // Borderize this tile
185+ void borderize(BaseMap* parent);
186+
187+ bool hasTable() const {
188+ return testFlags(statflags, TILESTATE_HAS_TABLE);
189+ }
190+ Item* getTable() const;
191+
192+ bool hasCarpet() const {
193+ return testFlags(statflags, TILESTATE_HAS_CARPET);
194+ }
195+ Item* getCarpet() const;
196+
197+ bool hasOptionalBorder() const {
198+ return testFlags(statflags, TILESTATE_OP_BORDER);
199+ }
200+ void setOptionalBorder(bool b) {
201+ if (b) {
202+ statflags |= TILESTATE_OP_BORDER;
203+ } else {
204+ statflags &= ~TILESTATE_OP_BORDER;
205+ }
206+ }
207+
208+ // Get the (first) wall of this tile
209+ Item* getWall() const;
210+ bool hasWall() const;
211+ // Remove all walls from the tile (for autowall) (only of those belonging to the specified brush
212+ void cleanWalls(WallBrush* wb);
213+ // Remove all walls from the tile
214+ void cleanWalls(bool dontdelete = false);
215+ // Add a wall item (same as just addItem, but an additional check to verify that it is a wall)
216+ void addWallItem(Item* item);
217+ // Wallize (name sucks, I know) this tile
218+ void wallize(BaseMap* parent);
219+ // Remove all tables from this tile
220+ void cleanTables(bool dontdelete = false);
221+ // Tableize (name sucks even worse, I know) this tile
222+ void tableize(BaseMap* parent);
223+ // Carpetize (name sucks even worse than last one, I know) this tile
224+ void carpetize(BaseMap* parent);
225+
226+ // Has to do with houses
227+ bool isHouseTile() const;
228+ uint32_t getHouseID() const;
229+ void setHouseID(uint32_t newHouseId);
230+ void addHouseExit(House* h);
231+ void removeHouseExit(House* h);
232+ bool isHouseExit() const;
233+ bool isTownExit(Map& map) const;
234+ const HouseExitList* getHouseExits() const;
235+ HouseExitList* getHouseExits();
236+ bool hasHouseExit(uint32_t exit) const;
237+ void setHouse(House* house);
238+ House* getHouse() const;
239+
240+ // Mapflags (PZ, PVPZONE etc.)
241+ void addZoneId(uint16_t _zoneId);
242+ void removeZoneId(uint16_t _zoneId);
243+ void clearZoneId();
244+ void setZoneIds(Tile* tile);
245+ const std::vector<uint16_t>& getZoneIds() const;
246+ uint16_t getZoneId() const;
247+
248+ void setMapFlags(uint16_t _flags);
249+ void unsetMapFlags(uint16_t _flags);
250+ uint16_t getMapFlags() const;
251+
252+ // Statflags (You really ought not to touch this)
253+ void setStatFlags(uint16_t _flags);
254+ void unsetStatFlags(uint16_t _flags);
255+ uint16_t getStatFlags() const;
256+
257+protected:
258+ union {
259+ struct {
260+ uint16_t mapflags;
261+ uint16_t statflags;
262+ };
263+ uint32_t flags;
264+ };
265+
266+ std::vector<uint16_t> zoneIds;
267+
268+private:
269+ uint8_t minimapColor;
270+
271+ Tile(const Tile& tile); // No copy
272+ Tile& operator=(const Tile& i); // Can't copy
273+ Tile& operator==(const Tile& i); // Can't compare
274+};
275+
276+bool tilePositionLessThan(const Tile* a, const Tile* b);
277+// This sorts them by draw order
278+bool tilePositionVisualLessThan(const Tile* a, const Tile* b);
279+
280+typedef std::vector<Tile*> TileVector;
281+typedef std::unordered_set<Tile*> TileSet;
282+typedef std::list<Tile*> TileList;
283+
284+inline bool Tile::hasWall() const {
285+ return getWall() != nullptr;
286+}
287+
288+inline bool Tile::isHouseTile() const {
289+ return house_id != 0;
290+}
291+
292+inline uint32_t Tile::getHouseID() const {
293+ return house_id;
294+}
295+
296+inline HouseExitList* Tile::getHouseExits() {
297+ return location->getHouseExits();
298+}
299+
300+inline const HouseExitList* Tile::getHouseExits() const {
301+ return location->getHouseExits();
302+}
303+
304+inline bool Tile::isHouseExit() const {
305+ const HouseExitList* house_exits = getHouseExits();
306+ if (house_exits) {
307+ return !house_exits->empty();
308+ }
309+ return false;
310+}
311+
312+inline bool Tile::hasHouseExit(uint32_t exit) const {
313+ const HouseExitList* house_exits = getHouseExits();
314+ if (house_exits) {
315+ for (HouseExitList::const_iterator iter = house_exits->begin(); iter != house_exits->end(); ++iter) {
316+ if (*iter == exit) {
317+ return true;
318+ }
319+ }
320+ }
321+ return false;
322+}
323+
324+inline void Tile::setMapFlags(uint16_t _flags) {
325+ mapflags = _flags | mapflags;
326+}
327+
328+inline void Tile::unsetMapFlags(uint16_t _flags) {
329+ mapflags &= ~_flags;
330+}
331+
332+inline uint16_t Tile::getMapFlags() const {
333+ return mapflags;
334+}
335+
336+inline void Tile::setStatFlags(uint16_t _flags) {
337+ statflags = _flags | statflags;
338+}
339+
340+inline void Tile::unsetStatFlags(uint16_t _flags) {
341+ statflags &= ~_flags;
342+}
343+
344+inline uint16_t Tile::getStatFlags() const {
345+ return statflags;
346+}
347+
348+inline void Tile::addZoneId(uint16_t _zoneId) {
349+ if (std::find(zoneIds.begin(), zoneIds.end(), _zoneId) == zoneIds.end()) {
350+ zoneIds.push_back(_zoneId);
351+ }
352+}
353+
354+inline void Tile::clearZoneId() {
355+ zoneIds.clear();
356+}
357+
358+inline void Tile::setZoneIds(Tile* tile) {
359+ zoneIds.clear();
360+ zoneIds.assign(tile->getZoneIds().begin(), tile->getZoneIds().end());
361+}
362+
363+inline void Tile::removeZoneId(uint16_t _zoneId) {
364+ const auto& itZone = std::find(zoneIds.begin(), zoneIds.end(), _zoneId);
365+ if (itZone != zoneIds.end()) {
366+ zoneIds.erase(itZone);
367+ }
368+}
369+
370+inline const std::vector<uint16_t>& Tile::getZoneIds() const {
371+ return zoneIds;
372+}
373+
374+inline uint16_t Tile::getZoneId() const {
375+ if (zoneIds.empty()) {
376+ return 0;
377+ }
378+
379+ return zoneIds.front();
380+}
381+
382+
383+#endif
A RD_Map_Editor/source/tileset.cpp +273-0 View file
@@ -0,0 +1,273 @@
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+
20+#include "tileset.h"
21+#include "creatures.h"
22+#include "creature_brush.h"
23+#include "items.h"
24+#include "raw_brush.h"
25+
26+Tileset::Tileset(Brushes& brushes, const std::string& name) :
27+ name(name),
28+ brushes(brushes) {
29+ ////
30+}
31+
32+Tileset::~Tileset() {
33+ for (TilesetCategoryArray::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
34+ delete *iter;
35+ }
36+}
37+
38+void Tileset::clear() {
39+ for (TilesetCategoryArray::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
40+ (*iter)->brushlist.clear();
41+ }
42+}
43+
44+bool Tileset::containsBrush(Brush* brush) const {
45+ for (TilesetCategoryArray::const_iterator iter = categories.begin(); iter != categories.end(); ++iter) {
46+ if ((*iter)->containsBrush(brush)) {
47+ return true;
48+ }
49+ }
50+
51+ return false;
52+}
53+
54+TilesetCategory* Tileset::getCategory(TilesetCategoryType type) {
55+ ASSERT(type >= TILESET_UNKNOWN && type <= TILESET_HOUSE);
56+ for (TilesetCategoryArray::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
57+ if ((*iter)->getType() == type) {
58+ return *iter;
59+ }
60+ }
61+ TilesetCategory* tsc = newd TilesetCategory(*this, type);
62+ categories.push_back(tsc);
63+ return tsc;
64+}
65+
66+bool TilesetCategory::containsBrush(Brush* brush) const {
67+ for (std::vector<Brush*>::const_iterator iter = brushlist.begin(); iter != brushlist.end(); ++iter) {
68+ if (*iter == brush) {
69+ return true;
70+ }
71+ }
72+
73+ return false;
74+}
75+
76+const TilesetCategory* Tileset::getCategory(TilesetCategoryType type) const {
77+ ASSERT(type >= TILESET_UNKNOWN && type <= TILESET_HOUSE);
78+ for (TilesetCategoryArray::const_iterator iter = categories.begin(); iter != categories.end(); ++iter) {
79+ if ((*iter)->getType() == type) {
80+ return *iter;
81+ }
82+ }
83+ return nullptr;
84+}
85+
86+void Tileset::loadCategory(pugi::xml_node node, wxArrayString& warnings) {
87+ TilesetCategory* category = nullptr;
88+ TilesetCategory* subCategory = nullptr;
89+
90+ const std::string& nodeName = as_lower_str(node.name());
91+ if (nodeName == "terrain") {
92+ category = getCategory(TILESET_TERRAIN);
93+ } else if (nodeName == "collections") {
94+ category = getCategory(TILESET_COLLECTION);
95+ } else if (nodeName == "doodad") {
96+ category = getCategory(TILESET_DOODAD);
97+ } else if (nodeName == "items") {
98+ category = getCategory(TILESET_ITEM);
99+ } else if (nodeName == "raw") {
100+ category = getCategory(TILESET_RAW);
101+ } else if (nodeName == "terrain_and_raw") {
102+ category = getCategory(TILESET_TERRAIN);
103+ subCategory = getCategory(TILESET_RAW);
104+ } else if (nodeName == "collections_and_raw") {
105+ category = getCategory(TILESET_COLLECTION);
106+ subCategory = getCategory(TILESET_RAW);
107+ } else if (nodeName == "collections_and_terrain") {
108+ category = getCategory(TILESET_COLLECTION);
109+ subCategory = getCategory(TILESET_TERRAIN);
110+ } else if (nodeName == "doodad_and_raw") {
111+ category = getCategory(TILESET_DOODAD);
112+ subCategory = getCategory(TILESET_RAW);
113+ } else if (nodeName == "items_and_raw") {
114+ category = getCategory(TILESET_ITEM);
115+ subCategory = getCategory(TILESET_RAW);
116+ } else if (nodeName == "creatures") {
117+ category = getCategory(TILESET_CREATURE);
118+ for (pugi::xml_node brushNode = node.first_child(); brushNode; brushNode = brushNode.next_sibling()) {
119+ const std::string& brushName = as_lower_str(brushNode.name());
120+ if (brushName != "creature") {
121+ continue;
122+ }
123+
124+ pugi::xml_attribute attribute;
125+ if (!(attribute = brushNode.attribute("name"))) {
126+ warnings.push_back("Couldn't read creature name tag of creature tileset");
127+ continue;
128+ }
129+
130+ const std::string& creatureName = attribute.as_string();
131+ CreatureType* ctype = g_creatures[creatureName];
132+ if (ctype) {
133+ CreatureBrush* brush;
134+ if (ctype->brush) {
135+ brush = ctype->brush;
136+ } else {
137+ brush = ctype->brush = newd CreatureBrush(ctype);
138+ brushes.addBrush(brush);
139+ }
140+ brush->flagAsVisible();
141+ category->brushlist.push_back(brush);
142+ } else {
143+ warnings.push_back(wxString("Unknown creature type \"") << wxstr(creatureName) << "\"");
144+ }
145+ }
146+ }
147+
148+ if (!category) {
149+ return;
150+ }
151+
152+ for (pugi::xml_node brushNode = node.first_child(); brushNode; brushNode = brushNode.next_sibling()) {
153+ category->loadBrush(brushNode, warnings);
154+ if (subCategory) {
155+ subCategory->loadBrush(brushNode, warnings);
156+ }
157+ }
158+}
159+
160+//
161+
162+TilesetCategory::TilesetCategory(Tileset& parent, TilesetCategoryType type) :
163+ type(type), tileset(parent) {
164+ ASSERT(type >= TILESET_UNKNOWN && type <= TILESET_HOUSE);
165+}
166+
167+TilesetCategory::~TilesetCategory() {
168+ ASSERT(type >= TILESET_UNKNOWN && type <= TILESET_HOUSE);
169+}
170+
171+bool TilesetCategory::isTrivial() const {
172+ return (type == TILESET_ITEM) || (type == TILESET_RAW);
173+}
174+
175+void TilesetCategory::loadBrush(pugi::xml_node node, wxArrayString& warnings) {
176+ pugi::xml_attribute attribute;
177+
178+ std::string brushName = node.attribute("after").as_string();
179+ if ((attribute = node.attribute("afteritem"))) {
180+ ItemType& it = g_items[attribute.as_ushort()];
181+ if (it.id != 0) {
182+ brushName = it.raw_brush ? it.raw_brush->getName() : std::string();
183+ }
184+ }
185+
186+ const std::string& nodeName = as_lower_str(node.name());
187+ if (nodeName == "brush") {
188+ if (!(attribute = node.attribute("name"))) {
189+ return;
190+ }
191+
192+ Brush* brush = tileset.brushes.getBrush(attribute.as_string());
193+ if (brush) {
194+ auto insertPosition = brushlist.end();
195+ if (!brushName.empty()) {
196+ for (auto itt = brushlist.begin(); itt != brushlist.end(); ++itt) {
197+ if ((*itt)->getName() == brushName) {
198+ insertPosition = ++itt;
199+ break;
200+ }
201+ }
202+ }
203+ brush->flagAsVisible();
204+ brushlist.insert(insertPosition, brush);
205+
206+ if (type == TILESET_COLLECTION) {
207+ brush->setCollection();
208+ }
209+ } else {
210+ warnings.push_back("Brush \"" + wxString(attribute.as_string(), wxConvUTF8) + "\" doesn't exist.");
211+ }
212+ } else if (nodeName == "item") {
213+ uint16_t fromId = 0, toId = 0;
214+ if (!(attribute = node.attribute("id"))) {
215+ if (!(attribute = node.attribute("fromid"))) {
216+ warnings.push_back("Couldn't read raw ids.");
217+ }
218+ toId = node.attribute("toid").as_ushort();
219+ }
220+
221+ fromId = attribute.as_ushort();
222+ toId = std::max<uint16_t>(fromId, toId);
223+
224+ std::vector<Brush*> tempBrushVector;
225+ for (uint16_t id = fromId; id <= toId; ++id) {
226+ ItemType& it = g_items[id];
227+ if (it.id == 0) {
228+ warnings.push_back(wxString::Format("Tileset: %s, Brush: %s, Previous %d, From: %d, To: %d", wxstr(tileset.name), wxstr(brushName), tileset.previousId, fromId, toId));
229+ warnings.push_back("Unknown item id #" + std::to_string(id) + ".");
230+ continue;
231+ }
232+
233+ RAWBrush* brush;
234+ if (it.raw_brush) {
235+ brush = it.raw_brush;
236+ if (type == TILESET_COLLECTION) {
237+ it.raw_brush->setCollection();
238+ }
239+ } else {
240+ brush = it.raw_brush = newd RAWBrush(it.id);
241+ it.has_raw = true;
242+ if (type == TILESET_COLLECTION) {
243+ it.raw_brush->setCollection();
244+ }
245+ tileset.brushes.addBrush(brush); // This will take care of cleaning up afterwards
246+ }
247+
248+ if (type == TILESET_COLLECTION) {
249+ it.collection_brush = brush;
250+ }
251+
252+ if (it.doodad_brush == nullptr && !isTrivial()) {
253+ it.doodad_brush = brush;
254+ }
255+
256+ brush->flagAsVisible();
257+ tempBrushVector.push_back(brush);
258+
259+ tileset.previousId = id;
260+ }
261+
262+ auto insertPosition = brushlist.end();
263+ if (!brushName.empty()) {
264+ for (auto itt = brushlist.begin(); itt != brushlist.end(); ++itt) {
265+ if ((*itt)->getName() == brushName) {
266+ insertPosition = ++itt;
267+ break;
268+ }
269+ }
270+ }
271+ brushlist.insert(insertPosition, tempBrushVector.begin(), tempBrushVector.end());
272+ }
273+}
A RD_Map_Editor/source/tileset.h +97-0 View file
@@ -0,0 +1,97 @@
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_TILESET_H_
19+#define RME_TILESET_H_
20+
21+class Brushes;
22+
23+enum TilesetCategoryType {
24+ TILESET_UNKNOWN,
25+ TILESET_TERRAIN,
26+ TILESET_CREATURE,
27+ TILESET_DOODAD,
28+ TILESET_COLLECTION,
29+ TILESET_ITEM,
30+ TILESET_RAW,
31+ TILESET_HOUSE,
32+ TILESET_WAYPOINT,
33+};
34+
35+class TilesetCategory {
36+public:
37+ TilesetCategory(Tileset& parent, TilesetCategoryType type);
38+ ~TilesetCategory();
39+
40+ bool isTrivial() const;
41+ TilesetCategoryType getType() const {
42+ return type;
43+ }
44+ size_t size() const {
45+ return brushlist.size();
46+ }
47+
48+ void loadBrush(pugi::xml_node node, wxArrayString& warnings);
49+ void clear();
50+
51+ bool containsBrush(Brush* brush) const;
52+
53+protected:
54+ TilesetCategoryType type;
55+
56+public:
57+ std::vector<Brush*> brushlist;
58+ Tileset& tileset;
59+
60+private:
61+ TilesetCategory(const TilesetCategory&);
62+ TilesetCategory operator=(const TilesetCategory&);
63+};
64+
65+typedef std::vector<TilesetCategory*> TilesetCategoryArray;
66+
67+class Tileset {
68+public:
69+ Tileset(Brushes& brushes, const std::string& name);
70+ ~Tileset();
71+
72+ TilesetCategory* getCategory(TilesetCategoryType type);
73+ const TilesetCategory* getCategory(TilesetCategoryType type) const;
74+
75+ void loadCategory(pugi::xml_node node, wxArrayString& warnings);
76+ void clear();
77+
78+ bool containsBrush(Brush* brush) const;
79+
80+public:
81+ std::string name;
82+ int16_t previousId;
83+ TilesetCategoryArray categories;
84+
85+protected:
86+ Brushes& brushes;
87+
88+protected:
89+ Tileset(const Tileset&);
90+ Tileset operator=(const Tileset&);
91+
92+ friend class TilesetCategory;
93+};
94+
95+typedef std::map<std::string, Tileset*> TilesetContainer;
96+
97+#endif
A RD_Map_Editor/source/tileset_window.cpp +126-0 View file
@@ -0,0 +1,126 @@
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+
20+#include <wx/grid.h>
21+
22+#include "tile.h"
23+#include "item.h"
24+#include "complexitem.h"
25+#include "town.h"
26+#include "house.h"
27+#include "map.h"
28+#include "editor.h"
29+#include "creature.h"
30+#include "materials.h"
31+#include "tileset.h"
32+
33+#include "gui.h"
34+#include "application.h"
35+#include "tileset_window.h"
36+#include "container_properties_window.h"
37+
38+// ============================================================================
39+// Tileset Window
40+
41+BEGIN_EVENT_TABLE(TilesetWindow, wxDialog)
42+EVT_BUTTON(wxID_OK, TilesetWindow::OnClickOK)
43+EVT_BUTTON(wxID_CANCEL, TilesetWindow::OnClickCancel)
44+END_EVENT_TABLE()
45+
46+static constexpr int OUTFIT_COLOR_MAX = 133;
47+
48+TilesetWindow::TilesetWindow(wxWindow* win_parent, const Map* map, const Tile* tile_parent, Item* item, wxPoint pos) :
49+ ObjectPropertiesWindowBase(win_parent, "Move to Tileset", map, tile_parent, item, pos),
50+ palette_field(nullptr),
51+ tileset_field(nullptr) {
52+ ASSERT(edit_item);
53+
54+ wxSizer* topsizer = newd wxBoxSizer(wxVERTICAL);
55+ wxString description = "Move to Tileset";
56+
57+ wxSizer* boxsizer = newd wxStaticBoxSizer(wxVERTICAL, this, description);
58+
59+ wxFlexGridSizer* subsizer = newd wxFlexGridSizer(2, 10, 10);
60+ subsizer->AddGrowableCol(1);
61+
62+ subsizer->Add(newd wxStaticText(this, wxID_ANY, "ID " + i2ws(item->getID())));
63+ subsizer->Add(newd wxStaticText(this, wxID_ANY, "\"" + wxstr(item->getName()) + "\""));
64+
65+ subsizer->Add(newd wxStaticText(this, wxID_ANY, "Palette"));
66+ palette_field = newd wxChoice(this, wxID_ANY);
67+
68+ palette_field->Append("Terrain", newd int(TILESET_TERRAIN));
69+ palette_field->Append("Collections", newd int(TILESET_COLLECTION));
70+ palette_field->Append("Doodad", newd int(TILESET_DOODAD));
71+ palette_field->Append("Item", newd int(TILESET_ITEM));
72+ palette_field->Append("Raw", newd int(TILESET_RAW));
73+ palette_field->SetSelection(3);
74+
75+ palette_field->Connect(wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler(TilesetWindow::OnChangePalette), NULL, this);
76+ subsizer->Add(palette_field, wxSizerFlags(1).Expand());
77+
78+ subsizer->Add(newd wxStaticText(this, wxID_ANY, "Tileset"));
79+ tileset_field = newd wxChoice(this, wxID_ANY);
80+
81+ for (TilesetContainer::iterator iter = g_materials.tilesets.begin(); iter != g_materials.tilesets.end(); ++iter) {
82+ tileset_field->Append(wxstr(iter->second->name), newd std::string(iter->second->name));
83+ }
84+ tileset_field->SetSelection(0);
85+ subsizer->Add(tileset_field, wxSizerFlags(1).Expand());
86+
87+ boxsizer->Add(subsizer, wxSizerFlags(1).Expand());
88+
89+ topsizer->Add(boxsizer, wxSizerFlags(0).Expand().Border(wxLEFT | wxRIGHT, 20));
90+
91+ wxSizer* subsizer_ = newd wxBoxSizer(wxHORIZONTAL);
92+ subsizer_->Add(newd wxButton(this, wxID_OK, "OK"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10));
93+ subsizer_->Add(newd wxButton(this, wxID_CANCEL, "Cancel"), wxSizerFlags(1).Center().Border(wxTOP | wxBOTTOM, 10));
94+ topsizer->Add(subsizer_, wxSizerFlags(0).Center().Border(wxLEFT | wxRIGHT, 20));
95+
96+ SetSizerAndFit(topsizer);
97+ Centre(wxBOTH);
98+}
99+
100+void TilesetWindow::OnChangePalette(wxCommandEvent& WXUNUSED(event)) {
101+ tileset_field->Clear();
102+
103+ for (TilesetContainer::iterator iter = g_materials.tilesets.begin(); iter != g_materials.tilesets.end(); ++iter) {
104+ if (iter->second->getCategory(TilesetCategoryType(*static_cast<int*>(palette_field->GetClientData(palette_field->GetSelection()))))->brushlist.size() > 0) {
105+ tileset_field->Append(wxstr(iter->second->name), newd std::string(iter->second->name));
106+ }
107+ }
108+
109+ tileset_field->SetSelection(0);
110+}
111+
112+void TilesetWindow::OnClickOK(wxCommandEvent& WXUNUSED(event)) {
113+ if (edit_item) {
114+ TilesetCategoryType categoryType = TilesetCategoryType(*reinterpret_cast<int*>(palette_field->GetClientData(palette_field->GetSelection())));
115+ std::string tilesetName = *static_cast<std::string*>(tileset_field->GetClientData(tileset_field->GetSelection()));
116+
117+ g_materials.addToTileset(tilesetName, edit_item->getID(), categoryType);
118+ g_gui.PopupDialog("Added to Tileset", "'" + edit_item->getName() + "' has been added to tileset '" + tilesetName + "' of palette '" + palette_field->GetStringSelection() + "'", wxOK);
119+ }
120+ EndModal(1);
121+}
122+
123+void TilesetWindow::OnClickCancel(wxCommandEvent& WXUNUSED(event)) {
124+ // Just close this window
125+ EndModal(0);
126+}
A RD_Map_Editor/source/tileset_window.h +45-0 View file
@@ -0,0 +1,45 @@
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_TILESET_WINDOW_H_
19+#define RME_TILESET_WINDOW_H_
20+
21+#include "main.h"
22+
23+#include "common_windows.h"
24+
25+class ContainerItemButton;
26+class ContainerItemPopupMenu;
27+
28+class TilesetWindow : public ObjectPropertiesWindowBase {
29+public:
30+ TilesetWindow(wxWindow* parent, const Map* map, const Tile* tile, Item* item, wxPoint = wxDefaultPosition);
31+
32+ void OnChangePalette(wxCommandEvent& event);
33+
34+ void OnClickOK(wxCommandEvent&);
35+ void OnClickCancel(wxCommandEvent&);
36+
37+protected:
38+ // tileset
39+ wxChoice* palette_field;
40+ wxChoice* tileset_field;
41+
42+ DECLARE_EVENT_TABLE();
43+};
44+
45+#endif
A RD_Map_Editor/source/town.cpp +80-0 View file
@@ -0,0 +1,80 @@
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+
20+#include "town.h"
21+
22+#include "map.h"
23+#include "tile.h"
24+
25+Towns::Towns() {
26+ ////
27+}
28+
29+Towns::~Towns() {
30+ clear();
31+}
32+
33+void Towns::clear() {
34+ TownMap::const_iterator it = begin();
35+ while (it != end()) {
36+ delete it->second;
37+ ++it;
38+ }
39+ towns.clear();
40+}
41+
42+bool Towns::addTown(Town* town) {
43+ TownMap::iterator it = find(town->getID());
44+ if (it != end()) {
45+ return false;
46+ }
47+ towns[town->getID()] = town;
48+ return true;
49+}
50+
51+uint32_t Towns::getEmptyID() {
52+ uint32_t empty = 0;
53+ for (TownMap::iterator it = begin(); it != end(); ++it) {
54+ if (it->second->getID() > empty) {
55+ empty = it->second->getID();
56+ }
57+ }
58+ return empty + 1;
59+}
60+
61+Town* Towns::getTown(std::string& name) {
62+ for (TownMap::iterator it = begin(); it != end(); ++it) {
63+ if (it->second->getName() == name) {
64+ return it->second;
65+ }
66+ }
67+ return nullptr;
68+}
69+
70+Town* Towns::getTown(uint32_t id) {
71+ TownMap::iterator it = find(id);
72+ if (it != end()) {
73+ return it->second;
74+ }
75+ return nullptr;
76+}
77+
78+void Town::setTemplePosition(const Position& pos) {
79+ templepos = pos;
80+}
A RD_Map_Editor/source/town.h +108-0 View file
@@ -0,0 +1,108 @@
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_TOWN_H_
19+#define RME_TOWN_H_
20+
21+#include "position.h"
22+
23+class Town {
24+public:
25+ Town(uint32_t _id) :
26+ id(_id), name("") { }
27+ Town(const Town& copy) :
28+ id(copy.id), name(copy.name), templepos(copy.templepos) { }
29+ ~Town() { }
30+
31+ const std::string& getName() const {
32+ return name;
33+ }
34+ void setName(const std::string& newName) {
35+ name = newName;
36+ }
37+
38+ const Position& getTemplePosition() const {
39+ return templepos;
40+ }
41+ void setTemplePosition(const Position& _pos);
42+
43+ uint32_t getID() const {
44+ return id;
45+ }
46+ void setID(uint32_t _id) {
47+ id = _id;
48+ }
49+
50+private:
51+ uint32_t id;
52+ std::string name;
53+ Position templepos;
54+};
55+
56+typedef std::map<uint32_t, Town*> TownMap;
57+
58+class Towns {
59+public:
60+ Towns();
61+ ~Towns();
62+
63+ // Clears the townmap
64+ void clear();
65+
66+ uint32_t count() const {
67+ return towns.size();
68+ }
69+
70+ bool addTown(Town* town);
71+ uint32_t getEmptyID();
72+
73+ Town* getTown(std::string& townname);
74+ Town* getTown(uint32_t _townid);
75+
76+ TownMap::const_iterator begin() const {
77+ return towns.begin();
78+ }
79+ TownMap::const_iterator end() const {
80+ return towns.end();
81+ }
82+ TownMap::const_iterator find(uint32_t id) const {
83+ return towns.find(id);
84+ }
85+ TownMap::iterator begin() {
86+ return towns.begin();
87+ }
88+ TownMap::iterator end() {
89+ return towns.end();
90+ }
91+ TownMap::iterator find(uint32_t id) {
92+ return towns.find(id);
93+ }
94+#ifdef __VISUALC__ // C++0x compliance to some degree :)
95+ TownMap::iterator erase(TownMap::iterator iter) {
96+ return towns.erase(iter);
97+ }
98+#else
99+ void erase(TownMap::iterator iter) {
100+ towns.erase(iter);
101+ }
102+#endif
103+
104+private:
105+ TownMap towns;
106+};
107+
108+#endif
A RD_Map_Editor/source/updater.cpp +91-0 View file
@@ -0,0 +1,91 @@
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+
20+#ifdef _USE_UPDATER_
21+
22+ #include <wx/url.h>
23+
24+ #include "json.h"
25+
26+ #include "updater.h"
27+
28+const wxEventType EVT_UPDATE_CHECK_FINISHED = wxNewEventType();
29+
30+UpdateChecker::UpdateChecker() {
31+ ////
32+}
33+
34+UpdateChecker::~UpdateChecker() {
35+ ////
36+}
37+
38+void UpdateChecker::connect(wxEvtHandler* receiver) {
39+ wxString address = "http://www.remeresmapeditor.com/update.php";
40+ address << "?os="
41+ <<
42+ #ifdef __WINDOWS__
43+ "windows";
44+ #elif __LINUX__
45+ "linux";
46+ #else
47+ "unknown";
48+ #endif
49+ address << "&verid=" << __RME_VERSION_ID__;
50+ #ifdef __EXPERIMENTAL__
51+ address << "&beta";
52+ #endif
53+ wxURL* url = newd wxURL(address);
54+ UpdateConnectionThread* connection = newd UpdateConnectionThread(receiver, url);
55+ connection->Execute();
56+}
57+
58+UpdateConnectionThread::UpdateConnectionThread(wxEvtHandler* receiver, wxURL* url) :
59+ receiver(receiver),
60+ url(url) {
61+ ////
62+}
63+
64+UpdateConnectionThread::~UpdateConnectionThread() {
65+ ////
66+}
67+
68+wxThread::ExitCode UpdateConnectionThread::Entry() {
69+ wxInputStream* input = url->GetInputStream();
70+ if (!input) {
71+ delete input;
72+ delete url;
73+ return 0;
74+ }
75+
76+ std::string data;
77+ while (!input->Eof()) {
78+ data += input->GetC();
79+ }
80+
81+ delete input;
82+ delete url;
83+ wxCommandEvent event(EVT_UPDATE_CHECK_FINISHED);
84+ event.SetClientData(newd std::string(data));
85+ if (receiver) {
86+ receiver->AddPendingEvent(event);
87+ }
88+ return 0;
89+}
90+
91+#endif
A RD_Map_Editor/source/updater.h +57-0 View file
@@ -0,0 +1,57 @@
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+#ifdef _USE_UPDATER_
19+
20+ #ifndef RME_UPDATER_H_
21+ #define RME_UPDATER_H_
22+
23+ #include "threads.h"
24+
25+extern const wxEventType EVT_UPDATE_CHECK_FINISHED;
26+
27+ #define EVT_ON_UPDATE_CHECK_FINISHED(id, fn) \
28+ DECLARE_EVENT_TABLE_ENTRY( \
29+ EVT_UPDATE_CHECK_FINISHED, id, wxID_ANY, \
30+ (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxCommandEventFunction, &fn), \
31+ (wxObject*)nullptr \
32+ ),
33+
34+class wxURL;
35+
36+class UpdateConnectionThread : public DetachedThread {
37+public:
38+ UpdateConnectionThread(wxEvtHandler* receiver, wxURL* url);
39+ virtual ~UpdateConnectionThread();
40+
41+protected:
42+ virtual ExitCode Entry();
43+ wxEvtHandler* receiver;
44+ wxURL* url;
45+};
46+
47+class UpdateChecker {
48+public:
49+ UpdateChecker();
50+ ~UpdateChecker();
51+
52+ void connect(wxEvtHandler* receiver);
53+};
54+
55+ #endif
56+
57+#endif
Top