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/carpet_brush.cpp +311-0 View file
@@ -0,0 +1,311 @@
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 "carpet_brush.h"
21+
22+#include "basemap.h"
23+#include "items.h"
24+
25+//=============================================================================
26+// Carpet brush
27+
28+uint32_t CarpetBrush::carpet_types[256];
29+
30+CarpetBrush::CarpetBrush() :
31+ look_id(0) {
32+ ////
33+}
34+
35+CarpetBrush::~CarpetBrush() {
36+ ////
37+}
38+
39+bool CarpetBrush::load(pugi::xml_node node, wxArrayString& warnings) {
40+ pugi::xml_attribute attribute;
41+ if ((attribute = node.attribute("lookid"))) {
42+ look_id = attribute.as_ushort();
43+ }
44+
45+ if ((attribute = node.attribute("server_lookid"))) {
46+ look_id = g_items[attribute.as_ushort()].clientID;
47+ }
48+
49+ for (pugi::xml_node childNode = node.first_child(); childNode; childNode = childNode.next_sibling()) {
50+ if (as_lower_str(childNode.name()) != "carpet") {
51+ continue;
52+ }
53+
54+ uint32_t alignment;
55+ if ((attribute = childNode.attribute("align"))) {
56+ const std::string& alignString = attribute.as_string();
57+ alignment = AutoBorder::edgeNameToID(alignString);
58+ if (alignment == BORDER_NONE) {
59+ if (alignString == "center") {
60+ alignment = CARPET_CENTER;
61+ } else {
62+ warnings.push_back("Invalid alignment of carpet node\n");
63+ continue;
64+ }
65+ }
66+ } else {
67+ warnings.push_back("Could not read alignment tag of carpet node\n");
68+ continue;
69+ }
70+
71+ bool use_local_id = true;
72+ for (pugi::xml_node subChildNode = childNode.first_child(); subChildNode; subChildNode = subChildNode.next_sibling()) {
73+ if (as_lower_str(subChildNode.name()) != "item") {
74+ continue;
75+ }
76+
77+ use_local_id = false;
78+ if (!(attribute = subChildNode.attribute("id"))) {
79+ warnings.push_back("Could not read id tag of item node\n");
80+ continue;
81+ }
82+
83+ int32_t id = attribute.as_int();
84+ if (!(attribute = subChildNode.attribute("chance"))) {
85+ warnings.push_back("Could not read chance tag of item node\n");
86+ continue;
87+ }
88+
89+ int32_t chance = attribute.as_int();
90+
91+ ItemType& it = g_items[id];
92+ if (it.id == 0) {
93+ warnings.push_back("There is no itemtype with id " + std::to_string(id));
94+ continue;
95+ } else if (it.brush && it.brush != this) {
96+ warnings.push_back("Itemtype id " + std::to_string(id) + " already has a brush");
97+ continue;
98+ }
99+
100+ it.isCarpet = true;
101+ it.brush = this;
102+
103+ auto& alignItem = carpet_items[alignment];
104+ alignItem.total_chance += chance;
105+
106+ CarpetType t;
107+ t.id = id;
108+ t.chance = chance;
109+
110+ alignItem.items.push_back(t);
111+ }
112+
113+ if (use_local_id) {
114+ if (!(attribute = childNode.attribute("id"))) {
115+ warnings.push_back("Could not read id tag of carpet node\n");
116+ continue;
117+ }
118+
119+ uint16_t id = attribute.as_ushort();
120+
121+ ItemType& it = g_items[id];
122+ if (it.id == 0) {
123+ warnings.push_back("There is no itemtype with id " + std::to_string(id));
124+ return false;
125+ } else if (it.brush && it.brush != this) {
126+ warnings.push_back("Itemtype id " + std::to_string(id) + " already has a brush");
127+ return false;
128+ }
129+
130+ it.isCarpet = true;
131+ it.brush = this;
132+
133+ auto& alignItem = carpet_items[alignment];
134+ alignItem.total_chance = 1;
135+
136+ CarpetType carpetType;
137+ carpetType.id = id;
138+ carpetType.chance = 1;
139+
140+ alignItem.items.push_back(carpetType);
141+ }
142+ }
143+ return true;
144+}
145+
146+bool CarpetBrush::canDraw(BaseMap* map, const Position& position) const {
147+ return true;
148+}
149+
150+void CarpetBrush::draw(BaseMap* map, Tile* tile, void* parameter) {
151+ // Only remove old carpets if layering is disabled
152+ if (!g_settings.getBoolean(Config::LAYER_CARPETS)) {
153+ undraw(map, tile);
154+ }
155+ tile->addItem(Item::Create(getRandomCarpet(CARPET_CENTER)));
156+}
157+
158+void CarpetBrush::undraw(BaseMap* map, Tile* tile) {
159+ auto& items = tile->items;
160+ for (auto it = items.begin(); it != items.end();) {
161+ Item* item = *it;
162+ if (item->isCarpet()) {
163+ CarpetBrush* carpetBrush = item->getCarpetBrush();
164+ if (carpetBrush) {
165+ delete item;
166+ it = items.erase(it);
167+ } else {
168+ ++it;
169+ }
170+ } else {
171+ ++it;
172+ }
173+ }
174+}
175+
176+void CarpetBrush::doCarpets(BaseMap* map, Tile* tile) {
177+ static const auto hasMatchingCarpetBrushAtTile = [](BaseMap* map, CarpetBrush* carpetBrush, uint32_t x, uint32_t y, uint32_t z) -> bool {
178+ Tile* tile = map->getTile(x, y, z);
179+ if (!tile) {
180+ return false;
181+ }
182+
183+ for (Item* item : tile->items) {
184+ if (item->getCarpetBrush() == carpetBrush) {
185+ return true;
186+ }
187+ }
188+ return false;
189+ };
190+
191+ ASSERT(tile);
192+ if (!tile->hasCarpet()) {
193+ return;
194+ }
195+
196+ const Position& position = tile->getPosition();
197+ uint32_t x = position.x;
198+ uint32_t y = position.y;
199+ uint32_t z = position.z;
200+ /*
201+ static const std::pair<int32_t, int32_t> positionOffset[8] = {
202+ {-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}
203+ };
204+
205+ const auto& offset = positionOffset[i];
206+ if(neighbours[i] && hasMatchingCarpetBrushAtTile(map, carpetBrush, x + offset.first, y + offset.second, z)) {
207+ //
208+ }
209+ */
210+ for (Item* item : tile->items) {
211+ ASSERT(item);
212+
213+ CarpetBrush* carpetBrush = item->getCarpetBrush();
214+ if (!carpetBrush) {
215+ continue;
216+ }
217+
218+ bool neighbours[8] = { false };
219+ if (x == 0) {
220+ if (y == 0) {
221+ neighbours[0] = false;
222+ neighbours[1] = false;
223+ neighbours[2] = false;
224+ neighbours[3] = false;
225+ neighbours[4] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y, z);
226+ neighbours[5] = false;
227+ neighbours[6] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x, y + 1, z);
228+ neighbours[7] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y + 1, z);
229+ } else {
230+ neighbours[0] = false;
231+ neighbours[1] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x, y - 1, z);
232+ neighbours[2] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y - 1, z);
233+ neighbours[3] = false;
234+ neighbours[4] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y, z);
235+ neighbours[5] = false;
236+ neighbours[6] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x, y + 1, z);
237+ neighbours[7] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y + 1, z);
238+ }
239+ } else if (y == 0) {
240+ neighbours[0] = false;
241+ neighbours[1] = false;
242+ neighbours[2] = false;
243+ neighbours[3] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x - 1, y, z);
244+ neighbours[4] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y, z);
245+ neighbours[5] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x - 1, y + 1, z);
246+ neighbours[6] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x, y + 1, z);
247+ neighbours[7] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y + 1, z);
248+ } else {
249+ neighbours[0] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x - 1, y - 1, z);
250+ neighbours[1] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x, y - 1, z);
251+ neighbours[2] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y - 1, z);
252+ neighbours[3] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x - 1, y, z);
253+ neighbours[4] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y, z);
254+ neighbours[5] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x - 1, y + 1, z);
255+ neighbours[6] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x, y + 1, z);
256+ neighbours[7] = hasMatchingCarpetBrushAtTile(map, carpetBrush, x + 1, y + 1, z);
257+ }
258+
259+ uint32_t tileData = 0;
260+ for (uint32_t i = 0; i < 8; ++i) {
261+ if (neighbours[i]) {
262+ // Same table as this one, calculate what border
263+ tileData |= static_cast<uint32_t>(1) << i;
264+ }
265+ }
266+
267+ // border type is always valid.
268+ uint16_t id = carpetBrush->getRandomCarpet(static_cast<BorderType>(carpet_types[tileData]));
269+ if (id != 0) {
270+ item->setID(id);
271+ }
272+ }
273+}
274+
275+uint16_t CarpetBrush::getRandomCarpet(BorderType alignment) {
276+ static const auto findRandomCarpet = [](const CarpetNode& node) -> uint16_t {
277+ int32_t chance = random(1, node.total_chance);
278+ for (const CarpetType& carpetType : node.items) {
279+ if (chance <= carpetType.chance) {
280+ return carpetType.id;
281+ }
282+ chance -= carpetType.chance;
283+ }
284+ return 0;
285+ };
286+
287+ CarpetNode node = carpet_items[alignment];
288+ if (node.total_chance > 0) {
289+ return findRandomCarpet(node);
290+ }
291+
292+ node = carpet_items[CARPET_CENTER];
293+ if (alignment != CARPET_CENTER && node.total_chance > 0) {
294+ uint16_t id = findRandomCarpet(node);
295+ if (id != 0) {
296+ return id;
297+ }
298+ }
299+
300+ // Find an item to place on the tile, first center, then the rest.
301+ for (int32_t i = 0; i < 12; ++i) {
302+ node = carpet_items[i];
303+ if (node.total_chance > 0) {
304+ uint16_t id = findRandomCarpet(node);
305+ if (id != 0) {
306+ return id;
307+ }
308+ }
309+ }
310+ return 0;
311+}
A RD_Map_Editor/source/carpet_brush.h +90-0 View file
@@ -0,0 +1,90 @@
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_CARPET_BRUSH_H
19+#define RME_CARPET_BRUSH_H
20+
21+#include "brush.h"
22+
23+//=============================================================================
24+// Carpetbrush, for tables, and some things that behave like tables
25+// and with tables I really mean counters.
26+
27+class CarpetBrush : public Brush {
28+public:
29+ static void init();
30+
31+ CarpetBrush();
32+ virtual ~CarpetBrush();
33+
34+ bool isCarpet() const {
35+ return true;
36+ }
37+ CarpetBrush* asCarpet() {
38+ return static_cast<CarpetBrush*>(this);
39+ }
40+
41+ virtual bool load(pugi::xml_node node, wxArrayString& warnings);
42+
43+ virtual bool canDraw(BaseMap* map, const Position& position) const;
44+ virtual void draw(BaseMap* map, Tile* tile, void* parameter);
45+ virtual void undraw(BaseMap* map, Tile* tile);
46+
47+ static void doCarpets(BaseMap* map, Tile* tile);
48+
49+ virtual bool canDrag() const {
50+ return true;
51+ }
52+ virtual bool needBorders() const {
53+ return true;
54+ }
55+
56+ virtual int getLookID() const {
57+ return look_id;
58+ }
59+
60+ virtual std::string getName() const {
61+ return name;
62+ }
63+ virtual void setName(const std::string& newName) {
64+ name = newName;
65+ }
66+
67+protected:
68+ uint16_t getRandomCarpet(BorderType alignment);
69+
70+ struct CarpetType {
71+ int32_t chance;
72+ uint16_t id;
73+ };
74+
75+ struct CarpetNode {
76+ std::vector<CarpetType> items;
77+ int32_t total_chance;
78+
79+ CarpetNode() :
80+ items(), total_chance(0) { }
81+ };
82+
83+ CarpetNode carpet_items[14];
84+ std::string name;
85+ uint16_t look_id;
86+
87+ static uint32_t carpet_types[256];
88+};
89+
90+#endif
A RD_Map_Editor/source/client_version.h +276-0 View file
@@ -0,0 +1,276 @@
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_CLIENT_VERSION_H_
19+#define RME_CLIENT_VERSION_H_
20+
21+#include "main.h"
22+#include "settings.h"
23+
24+typedef int ClientVersionID;
25+
26+// Client versions
27+enum ClientVersions {
28+ CLIENT_VERSION_NONE = -1,
29+ CLIENT_VERSION_ALL = -2,
30+ CLIENT_VERSION_750 = 1,
31+ CLIENT_VERSION_755 = 2,
32+ CLIENT_VERSION_760 = 3,
33+ CLIENT_VERSION_770 = 3,
34+ CLIENT_VERSION_780 = 4,
35+ CLIENT_VERSION_790 = 5,
36+ CLIENT_VERSION_792 = 6,
37+ CLIENT_VERSION_800 = 7,
38+ CLIENT_VERSION_810 = 8,
39+ CLIENT_VERSION_811 = 9,
40+ CLIENT_VERSION_820 = 10, // After this version, OTBM stores charges as an attribute
41+ CLIENT_VERSION_830 = 11,
42+ CLIENT_VERSION_840 = 12,
43+ CLIENT_VERSION_841 = 13,
44+ CLIENT_VERSION_842 = 14,
45+ CLIENT_VERSION_850 = 15,
46+ CLIENT_VERSION_854_BAD = 16,
47+ CLIENT_VERSION_854 = 17,
48+ CLIENT_VERSION_855 = 18,
49+ CLIENT_VERSION_860_OLD = 19,
50+ CLIENT_VERSION_860 = 20,
51+ CLIENT_VERSION_861 = 21,
52+ CLIENT_VERSION_862 = 22,
53+ CLIENT_VERSION_870 = 23,
54+ CLIENT_VERSION_871 = 24,
55+ CLIENT_VERSION_872 = 25,
56+ CLIENT_VERSION_873 = 26,
57+ CLIENT_VERSION_900 = 27,
58+ CLIENT_VERSION_910 = 28,
59+ CLIENT_VERSION_920 = 29,
60+ CLIENT_VERSION_940 = 30,
61+ CLIENT_VERSION_944_V1 = 31,
62+ CLIENT_VERSION_944_V2 = 32,
63+ CLIENT_VERSION_944_V3 = 33,
64+ CLIENT_VERSION_944_V4 = 34,
65+ CLIENT_VERSION_946 = 35,
66+ CLIENT_VERSION_950 = 36,
67+ CLIENT_VERSION_952 = 37,
68+ CLIENT_VERSION_953 = 38,
69+ CLIENT_VERSION_954 = 39,
70+ CLIENT_VERSION_960 = 40,
71+ CLIENT_VERSION_961 = 41,
72+ CLIENT_VERSION_963 = 42,
73+ CLIENT_VERSION_970 = 43,
74+ CLIENT_VERSION_980 = 44,
75+ CLIENT_VERSION_981 = 45,
76+ CLIENT_VERSION_982 = 46,
77+ CLIENT_VERSION_983 = 47,
78+ CLIENT_VERSION_985 = 48,
79+ CLIENT_VERSION_986 = 49,
80+ CLIENT_VERSION_1010 = 50,
81+ CLIENT_VERSION_1020 = 51,
82+ CLIENT_VERSION_1021 = 52
83+};
84+
85+// OTBM versions
86+enum MapVersionID {
87+ MAP_OTBM_UNKNOWN = -1,
88+ MAP_OTBM_1 = 0,
89+ MAP_OTBM_2 = 1,
90+ MAP_OTBM_3 = 2,
91+ MAP_OTBM_4 = 3,
92+};
93+
94+// The composed version of a otbm file (otbm version, client version)
95+struct MapVersion {
96+ MapVersion() :
97+ otbm(MAP_OTBM_1), client(CLIENT_VERSION_NONE) { }
98+ MapVersion(MapVersionID m, ClientVersionID c) :
99+ otbm(m), client(c) { }
100+ MapVersionID otbm;
101+ ClientVersionID client;
102+};
103+
104+enum OtbFormatVersion : uint32_t {
105+ OTB_VERSION_1 = 1,
106+ OTB_VERSION_2 = 2,
107+ OTB_VERSION_3 = 3,
108+};
109+
110+// Represents an OTB version
111+struct OtbVersion {
112+ // '8.60', '7.40' etc.
113+ std::string name;
114+ // What file format the OTB is in (version 1..3)
115+ OtbFormatVersion format_version;
116+ // The minor version ID of the OTB (maps to CLIENT_VERSION in OTServ)
117+ ClientVersionID id;
118+};
119+
120+// Formats for the metadata file
121+enum DatFormat {
122+ DAT_FORMAT_UNKNOWN,
123+ DAT_FORMAT_74,
124+ DAT_FORMAT_755,
125+ DAT_FORMAT_78,
126+ DAT_FORMAT_86,
127+ DAT_FORMAT_96,
128+ DAT_FORMAT_1010,
129+ DAT_FORMAT_1050,
130+ DAT_FORMAT_1057
131+};
132+
133+enum DatFlags : uint8_t {
134+ DatFlagGround = 0,
135+ DatFlagGroundBorder = 1,
136+ DatFlagOnBottom = 2,
137+ DatFlagOnTop = 3,
138+ DatFlagContainer = 4,
139+ DatFlagStackable = 5,
140+ DatFlagForceUse = 6,
141+ DatFlagMultiUse = 7,
142+ DatFlagWritable = 8,
143+ DatFlagWritableOnce = 9,
144+ DatFlagFluidContainer = 10,
145+ DatFlagSplash = 11,
146+ DatFlagNotWalkable = 12,
147+ DatFlagNotMoveable = 13,
148+ DatFlagBlockProjectile = 14,
149+ DatFlagNotPathable = 15,
150+ DatFlagPickupable = 16,
151+ DatFlagHangable = 17,
152+ DatFlagHookSouth = 18,
153+ DatFlagHookEast = 19,
154+ DatFlagRotateable = 20,
155+ DatFlagLight = 21,
156+ DatFlagDontHide = 22,
157+ DatFlagTranslucent = 23,
158+ DatFlagDisplacement = 24,
159+ DatFlagElevation = 25,
160+ DatFlagLyingCorpse = 26,
161+ DatFlagAnimateAlways = 27,
162+ DatFlagMinimapColor = 28,
163+ DatFlagLensHelp = 29,
164+ DatFlagFullGround = 30,
165+ DatFlagLook = 31,
166+ DatFlagCloth = 32,
167+ DatFlagMarket = 33,
168+ DatFlagUsable = 34,
169+ DatFlagWrappable = 35,
170+ DatFlagUnwrappable = 36,
171+ DatFlagTopEffect = 37,
172+
173+ DatFlagFloorChange = 252,
174+ DatFlagNoMoveAnimation = 253, // 10.10: real value is 16, but we need to do this for backwards compatibility
175+ DatFlagChargeable = 254,
176+ DatFlagLast = 255
177+};
178+
179+// Represents a client file version
180+struct ClientData {
181+ DatFormat datFormat;
182+ uint32_t datSignature;
183+ uint32_t sprSignature;
184+};
185+
186+// typedef the client version
187+class ClientVersion;
188+typedef std::vector<ClientVersion*> ClientVersionList;
189+
190+class ClientVersion : boost::noncopyable {
191+public:
192+ ClientVersion(OtbVersion otb, std::string versionName, wxString path);
193+ ~ClientVersion() = default;
194+
195+ static void loadVersions();
196+ static void unloadVersions();
197+ static void saveVersions();
198+
199+ static ClientVersion* get(ClientVersionID id);
200+ static ClientVersion* get(std::string name);
201+ static ClientVersionList getVisible(std::string from, std::string to);
202+ static ClientVersionList getAll();
203+ static ClientVersionList getAllVisible();
204+ static ClientVersionList getAllForOTBMVersion(MapVersionID map_version);
205+ static ClientVersionList getAllVersionsSupportedForClientVersion(ClientVersion* v);
206+ static ClientVersion* getLatestVersion();
207+
208+ bool operator==(const ClientVersion& o) const {
209+ return otb.id == o.otb.id;
210+ }
211+
212+ bool hasValidPaths();
213+ bool loadValidPaths();
214+ void setClientPath(const FileName& dir);
215+
216+ bool isVisible() const;
217+ std::string getName() const;
218+
219+ ClientVersionID getID() const;
220+ MapVersionID getPrefferedMapVersionID() const;
221+ OtbVersion getOTBVersion() const;
222+ DatFormat getDatFormatForSignature(uint32_t signature) const;
223+ ClientVersionList getExtensionsSupported() const;
224+
225+ FileName getDataPath() const;
226+ FileName getLocalDataPath() const;
227+ FileName getClientPath() const {
228+ return client_path;
229+ }
230+ wxFileName getMetadataPath() const {
231+ return metadata_path;
232+ }
233+ wxFileName getSpritesPath() const {
234+ return sprites_path;
235+ }
236+
237+private:
238+ OtbVersion otb;
239+
240+ std::string name;
241+ bool visible;
242+ bool usesFuckedUpCharges;
243+
244+ std::vector<MapVersionID> map_versions_supported;
245+ MapVersionID preferred_map_version;
246+ std::vector<ClientData> data_versions;
247+ std::vector<ClientVersion*> extension_versions;
248+
249+ wxString data_path;
250+ FileName client_path;
251+ wxFileName metadata_path;
252+ wxFileName sprites_path;
253+
254+private:
255+ static void loadOTBInfo(pugi::xml_node otb_nodes);
256+ static void loadVersion(pugi::xml_node client_node);
257+ static void loadVersionExtensions(pugi::xml_node client_node);
258+
259+ // All versions
260+ typedef std::map<ClientVersionID, ClientVersion*> VersionMap;
261+ static VersionMap client_versions;
262+ static ClientVersion* latest_version;
263+
264+ // All otbs
265+ typedef std::map<std::string, OtbVersion> OtbMap;
266+ static OtbMap otb_versions;
267+};
268+
269+inline int VersionComparisonPredicate(ClientVersion* a, ClientVersion* b) {
270+ if (a->getID() < b->getID()) {
271+ return 1;
272+ }
273+ return 0;
274+}
275+
276+#endif
A RD_Map_Editor/source/CMakeLists.txt +208-0 View file
@@ -0,0 +1,208 @@
1+set(rme_H
2+${CMAKE_CURRENT_LIST_DIR}/about_window.h
3+${CMAKE_CURRENT_LIST_DIR}/action.h
4+${CMAKE_CURRENT_LIST_DIR}/application.h
5+${CMAKE_CURRENT_LIST_DIR}/artprovider.h
6+${CMAKE_CURRENT_LIST_DIR}/basemap.h
7+${CMAKE_CURRENT_LIST_DIR}/border_editor_window.h
8+${CMAKE_CURRENT_LIST_DIR}/browse_tile_window.h
9+${CMAKE_CURRENT_LIST_DIR}/brush.h
10+${CMAKE_CURRENT_LIST_DIR}/brush_enums.h
11+${CMAKE_CURRENT_LIST_DIR}/carpet_brush.h
12+${CMAKE_CURRENT_LIST_DIR}/client_version.h
13+${CMAKE_CURRENT_LIST_DIR}/common.h
14+${CMAKE_CURRENT_LIST_DIR}/common_windows.h
15+${CMAKE_CURRENT_LIST_DIR}/complexitem.h
16+${CMAKE_CURRENT_LIST_DIR}/con_vector.h
17+${CMAKE_CURRENT_LIST_DIR}/container_properties_window.h
18+${CMAKE_CURRENT_LIST_DIR}/copybuffer.h
19+${CMAKE_CURRENT_LIST_DIR}/creature.h
20+${CMAKE_CURRENT_LIST_DIR}/creature_brush.h
21+${CMAKE_CURRENT_LIST_DIR}/creatures.h
22+${CMAKE_CURRENT_LIST_DIR}/creature_sprite_manager.h
23+${CMAKE_CURRENT_LIST_DIR}/dat_debug_view.h
24+${CMAKE_CURRENT_LIST_DIR}/dcbutton.h
25+${CMAKE_CURRENT_LIST_DIR}/definitions.h
26+${CMAKE_CURRENT_LIST_DIR}/doodad_brush.h
27+${CMAKE_CURRENT_LIST_DIR}/editor.h
28+${CMAKE_CURRENT_LIST_DIR}/editor_tabs.h
29+${CMAKE_CURRENT_LIST_DIR}/extension.h
30+${CMAKE_CURRENT_LIST_DIR}/extension_window.h
31+${CMAKE_CURRENT_LIST_DIR}/find_item_window.h
32+${CMAKE_CURRENT_LIST_DIR}/filehandle.h
33+${CMAKE_CURRENT_LIST_DIR}/graphics.h
34+${CMAKE_CURRENT_LIST_DIR}/ground_brush.h
35+${CMAKE_CURRENT_LIST_DIR}/gui.h
36+${CMAKE_CURRENT_LIST_DIR}/gui_ids.h
37+${CMAKE_CURRENT_LIST_DIR}/house.h
38+${CMAKE_CURRENT_LIST_DIR}/house_brush.h
39+${CMAKE_CURRENT_LIST_DIR}/house_exit_brush.h
40+${CMAKE_CURRENT_LIST_DIR}/iomap.h
41+${CMAKE_CURRENT_LIST_DIR}/iomap_otbm.h
42+#${CMAKE_CURRENT_LIST_DIR}/iomap_otmm.h
43+${CMAKE_CURRENT_LIST_DIR}/item.h
44+${CMAKE_CURRENT_LIST_DIR}/item_attributes.h
45+${CMAKE_CURRENT_LIST_DIR}/items.h
46+${CMAKE_CURRENT_LIST_DIR}/json.h
47+${CMAKE_CURRENT_LIST_DIR}/light_drawer.h
48+${CMAKE_CURRENT_LIST_DIR}/live_action.h
49+${CMAKE_CURRENT_LIST_DIR}/live_client.h
50+${CMAKE_CURRENT_LIST_DIR}/live_packets.h
51+${CMAKE_CURRENT_LIST_DIR}/live_peer.h
52+${CMAKE_CURRENT_LIST_DIR}/live_server.h
53+${CMAKE_CURRENT_LIST_DIR}/live_socket.h
54+${CMAKE_CURRENT_LIST_DIR}/live_tab.h
55+${CMAKE_CURRENT_LIST_DIR}/main.h
56+${CMAKE_CURRENT_LIST_DIR}/main_menubar.h
57+${CMAKE_CURRENT_LIST_DIR}/main_toolbar.h
58+${CMAKE_CURRENT_LIST_DIR}/map.h
59+${CMAKE_CURRENT_LIST_DIR}/map_allocator.h
60+${CMAKE_CURRENT_LIST_DIR}/map_display.h
61+${CMAKE_CURRENT_LIST_DIR}/map_drawer.h
62+${CMAKE_CURRENT_LIST_DIR}/map_region.h
63+${CMAKE_CURRENT_LIST_DIR}/map_tab.h
64+${CMAKE_CURRENT_LIST_DIR}/map_window.h
65+${CMAKE_CURRENT_LIST_DIR}/materials.h
66+${CMAKE_CURRENT_LIST_DIR}/minimap_window.h
67+${CMAKE_CURRENT_LIST_DIR}/mt_rand.h
68+${CMAKE_CURRENT_LIST_DIR}/net_connection.h
69+${CMAKE_CURRENT_LIST_DIR}/numbertextctrl.h
70+${CMAKE_CURRENT_LIST_DIR}/old_properties_window.h
71+${CMAKE_CURRENT_LIST_DIR}/otml.h
72+${CMAKE_CURRENT_LIST_DIR}/outfit.h
73+${CMAKE_CURRENT_LIST_DIR}/palette_brushlist.h
74+${CMAKE_CURRENT_LIST_DIR}/palette_common.h
75+${CMAKE_CURRENT_LIST_DIR}/palette_creature.h
76+${CMAKE_CURRENT_LIST_DIR}/palette_house.h
77+${CMAKE_CURRENT_LIST_DIR}/palette_waypoints.h
78+${CMAKE_CURRENT_LIST_DIR}/palette_window.h
79+${CMAKE_CURRENT_LIST_DIR}/pngfiles.h
80+${CMAKE_CURRENT_LIST_DIR}/position.h
81+${CMAKE_CURRENT_LIST_DIR}/positionctrl.h
82+${CMAKE_CURRENT_LIST_DIR}/preferences.h
83+${CMAKE_CURRENT_LIST_DIR}/process_com.h
84+${CMAKE_CURRENT_LIST_DIR}/properties_window.h
85+${CMAKE_CURRENT_LIST_DIR}/raw_brush.h
86+${CMAKE_CURRENT_LIST_DIR}/replace_items_window.h
87+${CMAKE_CURRENT_LIST_DIR}/result_window.h
88+${CMAKE_CURRENT_LIST_DIR}/rme_forward_declarations.h
89+${CMAKE_CURRENT_LIST_DIR}/rme_net.h
90+${CMAKE_CURRENT_LIST_DIR}/selection.h
91+${CMAKE_CURRENT_LIST_DIR}/settings.h
92+${CMAKE_CURRENT_LIST_DIR}/spawn.h
93+${CMAKE_CURRENT_LIST_DIR}/spawn_brush.h
94+${CMAKE_CURRENT_LIST_DIR}/sprites.h
95+${CMAKE_CURRENT_LIST_DIR}/table_brush.h
96+${CMAKE_CURRENT_LIST_DIR}/templates.h
97+${CMAKE_CURRENT_LIST_DIR}/threads.h
98+${CMAKE_CURRENT_LIST_DIR}/tile.h
99+${CMAKE_CURRENT_LIST_DIR}/tileset.h
100+${CMAKE_CURRENT_LIST_DIR}/town.h
101+${CMAKE_CURRENT_LIST_DIR}/updater.h
102+${CMAKE_CURRENT_LIST_DIR}/wall_brush.h
103+${CMAKE_CURRENT_LIST_DIR}/waypoint_brush.h
104+${CMAKE_CURRENT_LIST_DIR}/waypoints.h
105+${CMAKE_CURRENT_LIST_DIR}/welcome_dialog.h
106+)
107+
108+set(rme_SRC
109+${CMAKE_CURRENT_LIST_DIR}/about_window.cpp
110+${CMAKE_CURRENT_LIST_DIR}/action.cpp
111+${CMAKE_CURRENT_LIST_DIR}/application.cpp
112+${CMAKE_CURRENT_LIST_DIR}/artprovider.cpp
113+${CMAKE_CURRENT_LIST_DIR}/basemap.cpp
114+${CMAKE_CURRENT_LIST_DIR}/border_editor_window.cpp
115+${CMAKE_CURRENT_LIST_DIR}/brush.cpp
116+${CMAKE_CURRENT_LIST_DIR}/brush_tables.cpp
117+${CMAKE_CURRENT_LIST_DIR}/browse_tile_window.cpp
118+${CMAKE_CURRENT_LIST_DIR}/positionctrl.cpp
119+${CMAKE_CURRENT_LIST_DIR}/carpet_brush.cpp
120+${CMAKE_CURRENT_LIST_DIR}/client_version.cpp
121+${CMAKE_CURRENT_LIST_DIR}/common.cpp
122+${CMAKE_CURRENT_LIST_DIR}/common_windows.cpp
123+${CMAKE_CURRENT_LIST_DIR}/complexitem.cpp
124+${CMAKE_CURRENT_LIST_DIR}/container_properties_window.cpp
125+${CMAKE_CURRENT_LIST_DIR}/copybuffer.cpp
126+${CMAKE_CURRENT_LIST_DIR}/creature_brush.cpp
127+${CMAKE_CURRENT_LIST_DIR}/creature.cpp
128+${CMAKE_CURRENT_LIST_DIR}/creatures.cpp
129+${CMAKE_CURRENT_LIST_DIR}/creature_sprite_manager.cpp
130+${CMAKE_CURRENT_LIST_DIR}/dat_debug_view.cpp
131+${CMAKE_CURRENT_LIST_DIR}/dcbutton.cpp
132+${CMAKE_CURRENT_LIST_DIR}/doodad_brush.cpp
133+${CMAKE_CURRENT_LIST_DIR}/editor.cpp
134+${CMAKE_CURRENT_LIST_DIR}/editor_tabs.cpp
135+${CMAKE_CURRENT_LIST_DIR}/eraser_brush.cpp
136+${CMAKE_CURRENT_LIST_DIR}/extension.cpp
137+${CMAKE_CURRENT_LIST_DIR}/extension_window.cpp
138+${CMAKE_CURRENT_LIST_DIR}/find_item_window.cpp
139+${CMAKE_CURRENT_LIST_DIR}/filehandle.cpp
140+${CMAKE_CURRENT_LIST_DIR}/graphics.cpp
141+${CMAKE_CURRENT_LIST_DIR}/ground_brush.cpp
142+${CMAKE_CURRENT_LIST_DIR}/gui.cpp
143+${CMAKE_CURRENT_LIST_DIR}/house_brush.cpp
144+${CMAKE_CURRENT_LIST_DIR}/house.cpp
145+${CMAKE_CURRENT_LIST_DIR}/house_exit_brush.cpp
146+${CMAKE_CURRENT_LIST_DIR}/iomap.cpp
147+${CMAKE_CURRENT_LIST_DIR}/iomap_otbm.cpp
148+#${CMAKE_CURRENT_LIST_DIR}/iomap_otmm.cpp
149+${CMAKE_CURRENT_LIST_DIR}/item_attributes.cpp
150+${CMAKE_CURRENT_LIST_DIR}/item.cpp
151+${CMAKE_CURRENT_LIST_DIR}/items.cpp
152+${CMAKE_CURRENT_LIST_DIR}/light_drawer.cpp
153+${CMAKE_CURRENT_LIST_DIR}/live_action.cpp
154+${CMAKE_CURRENT_LIST_DIR}/live_client.cpp
155+${CMAKE_CURRENT_LIST_DIR}/live_peer.cpp
156+${CMAKE_CURRENT_LIST_DIR}/live_server.cpp
157+${CMAKE_CURRENT_LIST_DIR}/live_socket.cpp
158+${CMAKE_CURRENT_LIST_DIR}/live_tab.cpp
159+${CMAKE_CURRENT_LIST_DIR}/main_menubar.cpp
160+${CMAKE_CURRENT_LIST_DIR}/main_toolbar.cpp
161+${CMAKE_CURRENT_LIST_DIR}/map.cpp
162+${CMAKE_CURRENT_LIST_DIR}/map_display.cpp
163+${CMAKE_CURRENT_LIST_DIR}/map_drawer.cpp
164+${CMAKE_CURRENT_LIST_DIR}/map_region.cpp
165+${CMAKE_CURRENT_LIST_DIR}/map_tab.cpp
166+${CMAKE_CURRENT_LIST_DIR}/map_window.cpp
167+${CMAKE_CURRENT_LIST_DIR}/materials.cpp
168+${CMAKE_CURRENT_LIST_DIR}/minimap_window.cpp
169+${CMAKE_CURRENT_LIST_DIR}/mkpch.cpp
170+${CMAKE_CURRENT_LIST_DIR}/mt_rand.cpp
171+${CMAKE_CURRENT_LIST_DIR}/net_connection.cpp
172+${CMAKE_CURRENT_LIST_DIR}/numbertextctrl.cpp
173+${CMAKE_CURRENT_LIST_DIR}/old_properties_window.cpp
174+${CMAKE_CURRENT_LIST_DIR}/palette_brushlist.cpp
175+${CMAKE_CURRENT_LIST_DIR}/palette_common.cpp
176+${CMAKE_CURRENT_LIST_DIR}/palette_creature.cpp
177+${CMAKE_CURRENT_LIST_DIR}/palette_house.cpp
178+${CMAKE_CURRENT_LIST_DIR}/palette_waypoints.cpp
179+${CMAKE_CURRENT_LIST_DIR}/palette_window.cpp
180+${CMAKE_CURRENT_LIST_DIR}/pngfiles.cpp
181+${CMAKE_CURRENT_LIST_DIR}/preferences.cpp
182+${CMAKE_CURRENT_LIST_DIR}/process_com.cpp
183+${CMAKE_CURRENT_LIST_DIR}/properties_window.cpp
184+${CMAKE_CURRENT_LIST_DIR}/raw_brush.cpp
185+${CMAKE_CURRENT_LIST_DIR}/replace_items_window.cpp
186+${CMAKE_CURRENT_LIST_DIR}/result_window.cpp
187+${CMAKE_CURRENT_LIST_DIR}/rme_net.cpp
188+${CMAKE_CURRENT_LIST_DIR}/selection.cpp
189+${CMAKE_CURRENT_LIST_DIR}/settings.cpp
190+${CMAKE_CURRENT_LIST_DIR}/spawn_brush.cpp
191+${CMAKE_CURRENT_LIST_DIR}/spawn.cpp
192+${CMAKE_CURRENT_LIST_DIR}/table_brush.cpp
193+${CMAKE_CURRENT_LIST_DIR}/templatemap76-74.cpp
194+${CMAKE_CURRENT_LIST_DIR}/templatemap81.cpp
195+${CMAKE_CURRENT_LIST_DIR}/templatemap854.cpp
196+${CMAKE_CURRENT_LIST_DIR}/templatemapclassic.cpp
197+${CMAKE_CURRENT_LIST_DIR}/tile.cpp
198+${CMAKE_CURRENT_LIST_DIR}/tileset.cpp
199+${CMAKE_CURRENT_LIST_DIR}/town.cpp
200+${CMAKE_CURRENT_LIST_DIR}/updater.cpp
201+${CMAKE_CURRENT_LIST_DIR}/wall_brush.cpp
202+${CMAKE_CURRENT_LIST_DIR}/waypoint_brush.cpp
203+${CMAKE_CURRENT_LIST_DIR}/waypoints.cpp
204+${CMAKE_CURRENT_LIST_DIR}/welcome_dialog.cpp
205+${CMAKE_CURRENT_LIST_DIR}/json/json_spirit_reader.cpp
206+${CMAKE_CURRENT_LIST_DIR}/json/json_spirit_value.cpp
207+${CMAKE_CURRENT_LIST_DIR}/json/json_spirit_writer.cpp
208+)
A RD_Map_Editor/source/color_utils.h +122-0 View file
@@ -0,0 +1,122 @@
1+#ifndef RME_COLOR_UTILS_H_
2+#define RME_COLOR_UTILS_H_
3+
4+#include <wx/wx.h>
5+#include <wx/image.h>
6+#include <ctime>
7+#include <random>
8+
9+class ColorUtils {
10+public:
11+ static void ShiftHue(wxImage& image, float hueShift) {
12+ if (!image.IsOk()) return;
13+
14+ // Make sure we have alpha channel
15+ if (!image.HasAlpha()) {
16+ image.InitAlpha();
17+ }
18+
19+ unsigned char* data = image.GetData();
20+ unsigned char* alpha = image.GetAlpha();
21+ int width = image.GetWidth();
22+ int height = image.GetHeight();
23+
24+ for (int i = 0; i < width * height; ++i) {
25+ // Get alpha value first
26+ unsigned char a = alpha[i];
27+
28+ // Only process pixels that are not fully transparent
29+ if (a > 0) {
30+ int r = data[i * 3];
31+ int g = data[i * 3 + 1];
32+ int b = data[i * 3 + 2];
33+
34+ // Convert RGB to HSV
35+ float h, s, v;
36+ RGBtoHSV(r, g, b, h, s, v);
37+
38+ // Shift hue
39+ h += hueShift;
40+ if (h >= 360.0f) h -= 360.0f;
41+ else if (h < 0.0f) h += 360.0f;
42+
43+ // Convert back to RGB
44+ HSVtoRGB(h, s, v, r, g, b);
45+
46+ data[i * 3] = r;
47+ data[i * 3 + 1] = g;
48+ data[i * 3 + 2] = b;
49+ } else {
50+ // For fully transparent pixels, set RGB to white to avoid black edges
51+ data[i * 3] = 255;
52+ data[i * 3 + 1] = 255;
53+ data[i * 3 + 2] = 255;
54+ }
55+ }
56+ }
57+
58+ static float GetRandomHueShift() {
59+ static std::random_device rd;
60+ static std::mt19937 gen(rd());
61+ static std::uniform_real_distribution<float> dis(0.0f, 360.0f);
62+ return dis(gen);
63+ }
64+
65+private:
66+ static void RGBtoHSV(int r, int g, int b, float& h, float& s, float& v) {
67+ float rf = r / 255.0f;
68+ float gf = g / 255.0f;
69+ float bf = b / 255.0f;
70+
71+ float max = std::max(std::max(rf, gf), bf);
72+ float min = std::min(std::min(rf, gf), bf);
73+ float delta = max - min;
74+
75+ v = max;
76+ s = (max != 0.0f) ? (delta / max) : 0.0f;
77+
78+ if (delta == 0.0f) {
79+ h = 0.0f;
80+ } else {
81+ if (max == rf) {
82+ h = 60.0f * fmod(((gf - bf) / delta), 6.0f);
83+ } else if (max == gf) {
84+ h = 60.0f * (((bf - rf) / delta) + 2.0f);
85+ } else {
86+ h = 60.0f * (((rf - gf) / delta) + 4.0f);
87+ }
88+ }
89+
90+ if (h < 0.0f) h += 360.0f;
91+ }
92+
93+ static void HSVtoRGB(float h, float s, float v, int& r, int& g, int& b) {
94+ if (s == 0.0f) {
95+ r = g = b = static_cast<int>(v * 255.0f);
96+ return;
97+ }
98+
99+ h /= 60.0f;
100+ int i = static_cast<int>(floor(h));
101+ float f = h - i;
102+ float p = v * (1.0f - s);
103+ float q = v * (1.0f - s * f);
104+ float t = v * (1.0f - s * (1.0f - f));
105+
106+ float rf, gf, bf;
107+ switch (i % 6) {
108+ case 0: rf = v; gf = t; bf = p; break;
109+ case 1: rf = q; gf = v; bf = p; break;
110+ case 2: rf = p; gf = v; bf = t; break;
111+ case 3: rf = p; gf = q; bf = v; break;
112+ case 4: rf = t; gf = p; bf = v; break;
113+ case 5: rf = v; gf = p; bf = q; break;
114+ }
115+
116+ r = static_cast<int>(rf * 255.0f);
117+ g = static_cast<int>(gf * 255.0f);
118+ b = static_cast<int>(bf * 255.0f);
119+ }
120+};
121+
122+#endif // RME_COLOR_UTILS_H_
A RD_Map_Editor/source/common.cpp +262-0 View file
@@ -0,0 +1,262 @@
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 "common.h"
21+#include "math.h"
22+
23+#include <sstream>
24+#include <random>
25+#include <regex>
26+#include <algorithm>
27+
28+// random generator
29+std::mt19937& getRandomGenerator() {
30+ static std::random_device rd;
31+ static std::mt19937 generator(rd());
32+ return generator;
33+}
34+
35+int32_t uniform_random(int32_t minNumber, int32_t maxNumber) {
36+ static std::uniform_int_distribution<int32_t> uniformRand;
37+ if (minNumber == maxNumber) {
38+ return minNumber;
39+ } else if (minNumber > maxNumber) {
40+ std::swap(minNumber, maxNumber);
41+ }
42+ return uniformRand(getRandomGenerator(), std::uniform_int_distribution<int32_t>::param_type(minNumber, maxNumber));
43+}
44+
45+int32_t uniform_random(int32_t maxNumber) {
46+ return uniform_random(0, maxNumber);
47+}
48+
49+//
50+std::string i2s(const int _i) {
51+ static std::stringstream ss;
52+ ss.str("");
53+ ss << _i;
54+ return ss.str();
55+}
56+
57+std::string f2s(const double _d) {
58+ static std::stringstream ss;
59+ ss.str("");
60+ ss << _d;
61+ return ss.str();
62+}
63+
64+int s2i(const std::string s) {
65+ return atoi(s.c_str());
66+}
67+
68+double s2f(const std::string s) {
69+ return atof(s.c_str());
70+}
71+
72+wxString i2ws(const int _i) {
73+ wxString str;
74+ str << _i;
75+ return str;
76+}
77+
78+wxString f2ws(const double _d) {
79+ wxString str;
80+ str << _d;
81+ return str;
82+}
83+
84+int ws2i(const wxString s) {
85+ long _i;
86+ if (s.ToLong(&_i)) {
87+ return int(_i);
88+ }
89+ return 0;
90+}
91+
92+double ws2f(const wxString s) {
93+ double _d;
94+ if (s.ToDouble(&_d)) {
95+ return _d;
96+ }
97+ return 0.0;
98+}
99+
100+void replaceString(std::string& str, const std::string sought, const std::string replacement) {
101+ size_t pos = 0;
102+ size_t start = 0;
103+ size_t soughtLen = sought.length();
104+ size_t replaceLen = replacement.length();
105+ while ((pos = str.find(sought, start)) != std::string::npos) {
106+ str = str.substr(0, pos) + replacement + str.substr(pos + soughtLen);
107+ start = pos + replaceLen;
108+ }
109+}
110+
111+void trim_right(std::string& source, const std::string& t) {
112+ source.erase(source.find_last_not_of(t) + 1);
113+}
114+
115+void trim_left(std::string& source, const std::string& t) {
116+ source.erase(0, source.find_first_not_of(t));
117+}
118+
119+void to_lower_str(std::string& source) {
120+ std::transform(source.begin(), source.end(), source.begin(), tolower);
121+}
122+
123+void to_upper_str(std::string& source) {
124+ std::transform(source.begin(), source.end(), source.begin(), toupper);
125+}
126+
127+std::string as_lower_str(const std::string& other) {
128+ std::string ret = other;
129+ to_lower_str(ret);
130+ return ret;
131+}
132+
133+std::string as_upper_str(const std::string& other) {
134+ std::string ret = other;
135+ to_upper_str(ret);
136+ return ret;
137+}
138+
139+bool isFalseString(std::string& str) {
140+ if (str == "false" || str == "0" || str == "" || str == "no" || str == "not") {
141+ return true;
142+ }
143+ return false;
144+}
145+
146+bool isTrueString(std::string& str) {
147+ return !isFalseString(str);
148+}
149+
150+int random(int low, int high) {
151+ if (low == high) {
152+ return low;
153+ }
154+
155+ if (low > high) {
156+ return low;
157+ }
158+
159+ int range = high - low;
160+
161+ double dist = double(mt_randi()) / 0xFFFFFFFF;
162+ return low + min(range, int((1 + range) * dist));
163+}
164+
165+int random(int high) {
166+ return random(0, high);
167+}
168+
169+std::wstring string2wstring(const std::string& utf8string) {
170+ wxString s(utf8string.c_str(), wxConvUTF8);
171+ return std::wstring((const wchar_t*)s.c_str());
172+}
173+
174+std::string wstring2string(const std::wstring& widestring) {
175+ wxString s(widestring.c_str());
176+ return std::string((const char*)s.mb_str(wxConvUTF8));
177+}
178+
179+bool posFromClipboard(Position& position, int mapWidth, int mapHeight, const std::string& input) {
180+ std::string text_to_parse;
181+
182+ // If input is provided, use it directly, otherwise get from clipboard
183+ if (!input.empty()) {
184+ text_to_parse = input;
185+ } else {
186+ if (!wxTheClipboard->Open())
187+ return false;
188+
189+ wxTextDataObject data;
190+ if (!wxTheClipboard->GetData(data)) {
191+ wxTheClipboard->Close();
192+ return false;
193+ }
194+
195+ text_to_parse = data.GetText().ToStdString();
196+ wxTheClipboard->Close();
197+
198+ if (text_to_parse.empty())
199+ return false;
200+ }
201+
202+ // Extract just numbers, spaces, and commas
203+ std::string numbers_only;
204+ for (char c : text_to_parse) {
205+ // Accept digits, spaces, commas, and convert any whitespace/separator to space
206+ if (std::isdigit(c)) {
207+ numbers_only += c;
208+ } else if (std::isspace(c) || c == ',' || c == ';') {
209+ // Convert any separator to space
210+ if (!numbers_only.empty() && numbers_only.back() != ' ') {
211+ numbers_only += ' ';
212+ }
213+ }
214+ }
215+
216+ // Trim leading/trailing spaces
217+ while (!numbers_only.empty() && numbers_only.front() == ' ') {
218+ numbers_only.erase(0, 1);
219+ }
220+ while (!numbers_only.empty() && numbers_only.back() == ' ') {
221+ numbers_only.pop_back();
222+ }
223+
224+ // Split into numbers
225+ std::istringstream iss(numbers_only);
226+ std::vector<int> coords;
227+ int num;
228+ while (iss >> num) {
229+ coords.push_back(num);
230+ }
231+
232+ // If we have exactly 3 numbers, use them
233+ if (coords.size() >= 3) {
234+ const int tmpX = coords[0];
235+ const int tmpY = coords[1];
236+ const int tmpZ = coords[2];
237+
238+ const Position pastedPos = Position(tmpX, tmpY, tmpZ);
239+ if (pastedPos.isValid() && tmpX <= mapWidth && tmpY <= mapHeight) {
240+ position.x = tmpX;
241+ position.y = tmpY;
242+ position.z = tmpZ;
243+ return true;
244+ }
245+ }
246+
247+ return false;
248+}
249+
250+wxString b2yn(bool value) {
251+ return value ? "Yes" : "No";
252+}
253+
254+wxColor colorFromEightBit(int color) {
255+ if (color <= 0 || color >= 216) {
256+ return wxColor(0, 0, 0);
257+ }
258+ const uint8_t red = (uint8_t)(int(color / 36) % 6 * 51);
259+ const uint8_t green = (uint8_t)(int(color / 6) % 6 * 51);
260+ const uint8_t blue = (uint8_t)(color % 6 * 51);
261+ return wxColor(red, green, blue);
262+}
A RD_Map_Editor/source/common.h +122-0 View file
@@ -0,0 +1,122 @@
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_COMMONS_H_
19+#define RME_COMMONS_H_
20+
21+#include "main.h"
22+#include "position.h"
23+#include <stdio.h>
24+#include <stdlib.h>
25+#include <cmath>
26+#include <iomanip>
27+#include <string>
28+
29+#include "mt_rand.h"
30+
31+//
32+inline bool testFlags(size_t flags, size_t test) {
33+ return (flags & test) != 0;
34+}
35+
36+int32_t uniform_random(int32_t minNumber, int32_t maxNumber);
37+int32_t uniform_random(int32_t maxNumber);
38+
39+// Function-like convertions between float, int and doubles
40+std::string i2s(int i);
41+std::string f2s(double i);
42+int s2i(std::string s);
43+double s2f(std::string s);
44+wxString i2ws(int i);
45+wxString f2ws(double i);
46+int ws2i(wxString s);
47+double ws2f(wxString s);
48+double frand();
49+
50+// replaces all instances of sought in str with replacement
51+void replaceString(std::string& str, const std::string sought, const std::string replacement);
52+// Removes all characters in t from source (from either start or beginning of the string)
53+void trim_right(std::string& source, const std::string& t);
54+void trim_left(std::string& source, const std::string& t);
55+// Converts the argument to lower/uppercase
56+void to_lower_str(std::string& source);
57+void to_upper_str(std::string& source);
58+std::string as_lower_str(const std::string& other);
59+std::string as_upper_str(const std::string& other);
60+
61+// isFalseString returns true if the string is either "0", "false", "no", "not" or blank
62+// isTrueString returns the opposite value of isFalseString
63+bool isFalseString(std::string& str);
64+bool isTrueString(std::string& str);
65+
66+// Generates a random number between low and high using the mersenne twister
67+int random(int high);
68+int random(int low, int high);
69+
70+// Unicode conversions
71+std::wstring string2wstring(const std::string& utf8string);
72+std::string wstring2string(const std::wstring& widestring);
73+
74+// Gets position values from ClipBoard
75+bool posFromClipboard(Position& position, int mapWidth, int mapHeight, const std::string& input = "");
76+
77+// Returns 'yes' if the defined value is true or 'no' if it is false.
78+wxString b2yn(bool v);
79+
80+wxColor colorFromEightBit(int color);
81+
82+// Standard math functions
83+template <class T>
84+inline T abs(T t) {
85+ return (t < 0 ? -t : t);
86+}
87+
88+template <class T, class U>
89+inline T min(T t, U u) {
90+ return (t < u ? t : u);
91+}
92+
93+template <class T, class U>
94+T max(T t, U u) {
95+ return (t > u ? t : u);
96+}
97+
98+template <class T, class U, class V>
99+inline T min(T t, U u, V v) {
100+ int min = t;
101+ if (u < min) {
102+ min = u;
103+ }
104+ if (v < min) {
105+ min = v;
106+ }
107+ return min;
108+}
109+
110+template <class T, class U, class V>
111+inline T max(T t, U u, V v) {
112+ int max = t;
113+ if (u > max) {
114+ max = u;
115+ }
116+ if (v > max) {
117+ max = v;
118+ }
119+ return max;
120+}
121+
122+#endif
Top